So zählen Sie doppelte Elemente in Arraylist

1. Übersicht

In diesem kurzen Tutorial werden verschiedene Möglichkeiten zum Zählen der duplizierten Elemente in einer ArrayList vorgestellt .

2. Schleife mit Map.put ()

Unser erwartetes Ergebnis wäre ein Map- Objekt, das alle Elemente aus der Eingabeliste als Schlüssel und die Anzahl jedes Elements als Wert enthält.

Die einfachste Lösung, um dies zu erreichen, wäre, die Eingabeliste und für jedes Element zu durchlaufen:

  • Wenn die resultMap das Element enthält, erhöhen wir einen Zähler um 1
  • andernfalls wir setzen einen neuen Map - Eintrag (Element, 1) auf die Karte
public  Map countByClassicalLoop(List inputList) { Map resultMap = new HashMap(); for (T element : inputList) { if (resultMap.containsKey(element)) { resultMap.put(element, resultMap.get(element) + 1L); } else { resultMap.put(element, 1L); } } return resultMap; }

Diese Implementierung ist am besten kompatibel, da sie für alle modernen Java-Versionen funktioniert.

Wenn wir die Kompatibilität vor Java 8 nicht benötigen, können wir unsere Methode weiter vereinfachen:

public  Map countByForEachLoopWithGetOrDefault(List inputList) { Map resultMap = new HashMap(); inputList.forEach(e -> resultMap.put(e, resultMap.getOrDefault(e, 0L) + 1L)); return resultMap; }

Als Nächstes erstellen wir eine Eingabeliste, um die Methode zu testen:

private List INPUT_LIST = Lists.list( "expect1", "expect2", "expect2", "expect3", "expect3", "expect3", "expect4", "expect4", "expect4", "expect4"); 

Und jetzt überprüfen wir es:

private void verifyResult(Map resultMap) { assertThat(resultMap) .isNotEmpty().hasSize(4) .containsExactly( entry("expect1", 1L), entry("expect2", 2L), entry("expect3", 3L), entry("expect4", 4L)); } 

Wir werden dieses Testgeschirr für den Rest unserer Ansätze wiederverwenden.

3. Schleife mit Map.compute ()

In Java 8 wurde die praktische compute () -Methode in die Map- Oberfläche eingeführt. Wir können diese Methode auch anwenden:

public  Map countByForEachLoopWithMapCompute(List inputList) { Map resultMap = new HashMap(); inputList.forEach(e -> resultMap.compute(e, (k, v) -> v == null ? 1L : v + 1L)); return resultMap; }

Beachten Sie (k, v) -> v == null? 1L: v + 1L ist die Remapping-Funktion, die die BiFunction- Schnittstelle implementiert . Für einen bestimmten Schlüssel wird entweder der aktuelle Wert zurückgegeben, der um eins erhöht wurde (wenn der Schlüssel bereits in der Zuordnung vorhanden ist), oder der Standardwert eins wird zurückgegeben.

Um den Code besser lesbar zu machen, können wir die Neuzuordnungsfunktion in ihre Variable extrahieren oder sie sogar als Eingabeparameter für countByForEachLoopWithMapCompute verwenden.

4. Schleife mit Map.merge ()

Bei Verwendung von Map.compute () müssen die Nullwerte explizit behandelt werden - beispielsweise wenn keine Zuordnung für einen bestimmten Schlüssel vorhanden ist. Aus diesem Grund wir implementiert haben null Check in unserer Remapping - Funktion. Das sieht jedoch nicht schön aus.

Lassen Sie uns unseren Code mithilfe der Map.merge () -Methode weiter bereinigen :

public  Map countByForEachLoopWithMapMerge(List inputList) { Map resultMap = new HashMap(); inputList.forEach(e -> resultMap.merge(e, 1L, Long::sum)); return resultMap; }

Jetzt sieht der Code sauber und prägnant aus.

Lassen Sie uns erklären, wie merge () funktioniert. Wenn die Zuordnung für einen bestimmten Schlüssel nicht vorhanden ist oder sein Wert null ist, ordnet er den Schlüssel dem angegebenen Wert zu. Andernfalls wird mithilfe der Neuzuordnungsfunktion ein neuer Wert berechnet und die Zuordnung entsprechend aktualisiert.

Beachten Sie, dass wir diesmal Long :: sum als Implementierung der BiFunction- Schnittstelle verwendet haben.

5. Stream API Collectors.toMap ()

Da wir bereits über Java 8 gesprochen haben, können wir die leistungsstarke Stream-API nicht vergessen. Dank der Stream-API können wir das Problem sehr kompakt lösen.

Der toMap () -Kollektor hilft uns, die Eingabeliste in eine Map zu konvertieren :

public  Map countByStreamToMap(List inputList) { return inputList.stream().collect(Collectors.toMap(Function.identity(), v -> 1L, Long::sum)); }

Die toMap () ist ein praktischer Kollektor, mit dem wir den Stream in verschiedene Map- Implementierungen umwandeln können .

6. Streamen Sie die API Collectors.groupingBy () und Collectors.counting ()

Mit Ausnahme von toMap () kann unser Problem von zwei anderen Kollektoren gelöst werden, groupingBy ( ) und count () :

public  Map countByStreamGroupBy(List inputList) { return inputList.stream().collect(Collectors.groupingBy(k -> k, Collectors.counting())); }

Die ordnungsgemäße Verwendung von Java 8 Collectors macht unseren Code kompakt und einfach zu lesen.

7. Fazit

In diesem kurzen Artikel haben wir verschiedene Möglichkeiten zur Berechnung der Anzahl doppelter Elemente in einer Liste veranschaulicht.

Wenn Sie die ArrayList selbst auffrischen möchten, lesen Sie den Referenzartikel.

Wie immer ist der vollständige Quellcode auf GitHub verfügbar.