Hoe dubbele elementen in Arraylist te tellen

1. Overzicht

In deze korte tutorial zullen we enkele verschillende manieren bekijken om de gedupliceerde elementen in een ArrayList.

2. Loop met Map.put ()

Ons verwachte resultaat zou een zijn Kaart object, dat alle elementen uit de invoerlijst als sleutels bevat en het aantal van elk element als waarde.

De meest eenvoudige oplossing om dit te bereiken is om door de invoerlijst en voor elk element te lopen:

  • als het resultMap bevat het element, verhogen we een teller met 1
  • anders we leggen een nieuw kaartitem (element, 1) naar de kaart
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); }} retourneer resultMap; }

Deze implementatie heeft de beste compatibiliteit, aangezien deze werkt voor alle moderne Java-versies.

Als we de pre-Java 8-compatibiliteit niet nodig hebben, kunnen we onze methode verder vereenvoudigen:

openbare kaart countByForEachLoopWithGetOrDefault (lijst inputList) {Map resultMap = nieuwe HashMap (); inputList.forEach (e -> resultMap.put (e, resultMap.getOrDefault (e, 0L) + 1L)); return resultMap; }

Laten we vervolgens een invoerlijst maken om de methode te testen:

privélijst INPUT_LIST = Lists.list ("verwacht1", "verwacht2", "verwacht2", "verwacht3", "verwacht3", "verwacht3", "verwacht4", "verwacht4", "verwacht4", "verwacht4"); 

En laten we het nu verifiëren:

private void verifyResult (Map resultMap) {assertThat (resultMap) .isNotEmpty (). hasSize (4) .containsExactly (entry ("verwacht1", 1L), entry ("verwacht2", 2L), entry ("verwacht3", 3L) , entry ("verwacht4", 4L)); } 

We zullen dit testharnas hergebruiken voor de rest van onze benaderingen.

3. Loop met Map.compute ()

In Java 8 is het handige berekenen() methode is geïntroduceerd in de Kaart koppel. We kunnen ook gebruik maken van deze methode:

openbare kaart countByForEachLoopWithMapCompute (lijst inputList) {Map resultMap = nieuwe HashMap (); inputList.forEach (e -> resultMap.compute (e, (k, v) -> v == null? 1L: v + 1L)); return resultMap; }

Merk op (k, v) -> v == null? 1L: v + 1L is de remapping-functie die de BiFunction koppel. Voor een bepaalde sleutel retourneert het ofwel de huidige waarde verhoogd met één (als de sleutel al aanwezig is in de kaart) of retourneert het de standaardwaarde van één.

Om de code beter leesbaar te maken, we zouden de remapping-functie kunnen extraheren naar zijn variabele of deze zelfs als de invoerparameter voor de countByForEachLoopWithMapCompute.

4. Loop met Map.merge ()

Tijdens gebruik Map.compute (), we moeten omgaan met de nul waarden expliciet - bijvoorbeeld als er geen toewijzing voor een bepaalde sleutel bestaat. Daarom hebben we een nul bekijk onze remapping-functie. Dit ziet er echter niet mooi uit.

Laten we onze code verder opschonen met behulp van Map.merge () methode:

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

Nu ziet de code er schoon en beknopt uit.

Laten we uitleggen hoe samenvoegen() werken. Als de toewijzing voor een bepaalde sleutel niet bestaat, of de waarde ervan is nul, het associeert de sleutel met de opgegeven waarde. Anders berekent het een nieuwe waarde met behulp van de functie voor opnieuw toewijzen en werkt het de toewijzing dienovereenkomstig bij.

Merk op dat we deze keer gebruikten Long :: som als de BiFunction interface implementatie.

5. Stream API Collectors.toMap ()

Omdat we het al over Java 8 hebben gehad, mogen we de krachtige Stream API niet vergeten. Dankzij de Stream API kunnen we het probleem op een zeer compacte manier oplossen.

De in kaart brengen() collector helpt ons om de invoerlijst om te zetten in een Kaart:

openbare kaart countByStreamToMap (lijst inputList) {return inputList.stream (). collect (Collectors.toMap (Function.identity (), v -> 1L, Long :: som)); }

De in kaart brengen() is een handige verzamelaar die ons kan helpen om de stroom in iets anders te veranderen Kaart implementaties.

6. Stream API Collectors.groupingBy () en Collectors.counting ()

Behalve de in kaart brengen(), ons probleem kan worden opgelost door twee andere verzamelaars, groupingBy () en tellen ():

openbare kaart countByStreamGroupBy (lijst inputList) {return inputList.stream (). collect (Collectors.groupingBy (k -> k, Collectors.counting ())); }

Door het juiste gebruik van Java 8 Collectors is onze code compact en gemakkelijk te lezen.

7. Conclusie

In dit korte artikel hebben we verschillende manieren geïllustreerd om het aantal dubbele elementen in een lijst te berekenen.

Als je de ArrayList zelf wilt opfrissen, kun je het referentieartikel lezen.

Zoals altijd is de volledige broncode beschikbaar op GitHub.