1

My question is a little bit different. I have an ArrayList which contains some routes. For ex:

[ACD, CDE, DEB, EBJ, BJK, JKO, ACD, CDE, DEX, EXB, XBJ, BJK, JKO, KOL]

When I use HashMap for counting, it only prints me one string:

Most common route: ACD
This route repeats 2 times.

That is correct, BUT, the strings CDE, BJK and JKO also repeats 2 times. As I'm a beginner in programming, would you be so kind telling me what do I have to change in my code so it prints all the most common routes (strings).
Here's the code:

Map<String, Integer> stringsCount = new HashMap<>();

    for(String string: listaRuta)
    {
      Integer count = stringsCount.get(string);
      if(count == null) count = new Integer(0);
      count++;
      stringsCount.put(string,count);
    }

    Map.Entry<String,Integer> mostRepeated = null;
    for(Map.Entry<String, Integer> e: stringsCount.entrySet())
    {
        if(mostRepeated == null || mostRepeated.getValue()<e.getValue())
            mostRepeated = e;
    }
    if(mostRepeated != null)
        System.out.println("Most common route: " + mostRepeated.getKey());
        System.out.println("This route repeats " + mostRepeated.getValue() + " times.");
Gulllie
  • 523
  • 6
  • 21
szentmihaly
  • 39
  • 1
  • 13
  • 1
    Possible duplicate of [Find the most common String in ArrayList()](http://stackoverflow.com/questions/22989806/find-the-most-common-string-in-arraylist) – Joe Nov 16 '16 at 11:49
  • @Joe the OP asks for the most common strings in this question (more than one string if they occur). – user6904265 Nov 16 '16 at 12:47

4 Answers4

2

Here's a solution using a Bag and topOccurrences from Eclipse Collections.

MutableList<String> list =
        Lists.mutable.with("ACD", "CDE", "DEB", "EBJ", "BJK", "JKO", 
                "ACD", "CDE", "DEX", "EXB", "XBJ", "BJK", "JKO", "KOL");
MutableList<ObjectIntPair<String>> pairs =
        list.toBag().topOccurrences(1);
System.out.println(pairs);

Outputs:

[BJK:2, JKO:2, ACD:2, CDE:2]

A Bag is like a Map<Key, Integer> where the value is a count of the keys. Externally, the interface of a Bag is like a Collection<Key>. Eclipse Collections has primitive collections, so internally the HashBag implementation uses an ObjectIntHashMap to be more efficient.

The method topOccurrences on Bag has logic to handle ties, which is why more than one ObjectIntPair is returned in the result List.

Note: I am a committer for Eclipse Collections.

Donald Raab
  • 6,458
  • 2
  • 36
  • 44
1
package de.ninjaneers;

import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {

        String[] entries = {"ABC", "ABC", "DEF", "DEF", "DD", "MM"};
        Map<String, Long> counts = Arrays.stream(entries)
                .collect(Collectors.groupingBy(e -> e, Collectors.counting()));
        Long max = counts.entrySet().stream()
                .map(Map.Entry::getValue)
                .max(Long::compare)
                .orElse(0L);
        Map<String, Long> onlyTheMax = counts.entrySet().stream()
                .filter(e -> Objects.equals(max, e.getValue()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

    }
}

First you count all entries, second you get the max value and last you filter out all that are less then max. Sorry for the first to short example.

Christoph Grimmer
  • 4,210
  • 4
  • 40
  • 64
  • This builds the hasmap correctly, but does not give the most common strings of the original list as OP requested. – user6904265 Nov 16 '16 at 11:57
  • In this case, it prints me that BJK is the most common with 4 repeats. Which is not correct. @Christoph Grimmer-Dietrich – szentmihaly Nov 16 '16 at 12:05
  • @szentmihaly in this answer there is a different way to build the hashmap with string and counter (you also built the map correctly). There is not the implementation of how find the most common strings of the original list. – user6904265 Nov 16 '16 at 12:23
  • 1
    @user6904265 You are absolutely right my answer was to short. – Christoph Grimmer Nov 16 '16 at 13:41
1

Also I prefer lamba solution in order to build the hasmap. Once you have the map, this is a common use for your target:

int maxValue=(Collections.max(stringsCount.values()));  // This will return max value in the Hashmap
for (Entry<String, Integer> entry : stringsCount.entrySet()) {  // Iterate through the hashmap
    if (entry.getValue()==maxValue) {
        System.out.println(entry.getKey());     // Print the key with max value
    }
}

or in a more compact way with java 8 streams and lamba:

long maxValue=(Collections.max(stringsCount.values()));
stringsCount.entrySet()
     .stream()
     .filter(s -> s.getValue() == maxValue).forEach(System.out::println);
user6904265
  • 1,938
  • 1
  • 16
  • 21
0

A solution without Streams and Lambdas (easier to understand for beginners):

Test class

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Counter {

    public static void main(String[] args) {
    List<String> test = new ArrayList<>();
    test.add("a");
    test.add("b");
    test.add("b");
    test.add("c");
    test.add("c");
    test.add("c");

    Map<String, Integer> stringsCount = new HashMap<>();

    for (String s : test) {
        if (stringsCount.get(s) == null) {
        stringsCount.put(s, 1);
        } else {
        stringsCount.replace(s, stringsCount.get(s) + 1);
        }
    }

        for (Map.Entry entry : stringsCount.entrySet()) {
            System.out.println(entry.getKey() + ", " + entry.getValue());
        }
    }
}

Output

a, 1 b, 2 c, 3

Tim
  • 3,910
  • 8
  • 45
  • 80