user15006383
user15006383

Reputation:

Find most occurring String within ArrayList

I am kind of new to Java and wanted to ask how I can find the most occurring String within an ArrayList.

I have two classes. One holds game activities and the winner for those games. The other class is supposed to be the Event that holds all the games.

For the event class, I have to find the person with the most game activities won. I made an ArrayList in the events class that holds all the winners from the games. Now I need to find the name that occurs most often in the ArrayList and output the String.

private ArrayList<Game> games;

public String getEventWinner(){
ArrayList<String> winner;
winner = new ArrayList<String>();

for(Game game : games)
{
winner.add(game.getWinner());
}
return eventWinner;  
}

That gets me all the winners from the games in an ArrayList, but now I do not know how to proceed and couldn't find any answer online. Could somebody lead me in the right direction?

Upvotes: 0

Views: 112

Answers (2)

Nowhere Man
Nowhere Man

Reputation: 19545

Calculate the frequencies of the strings into a map, find the entry with max value, and return it.

With Stream API this could look like this:

public static String getEventWinner(List<Game> games) {
    return games.stream()
        .map(Game::getWinner) // Stream<String>
        .collect(Collectors.groupingBy(
            winner -> winner, LinkedHashMap::new,
            Collectors.summingInt(x -> 1)
        )) // build the frequency map
        .entrySet().stream()
        .max(Map.Entry.comparingByValue()) // Optional<Map.Entry<String, Integer>>
        .map(Map.Entry::getKey) // the key - winner name
        .orElse(null);
}

Here LinkedHashMap is used as a tie breaker, however, it allows to select as a winner the person who appeared earlier in the game list.

Test:

System.out.println(getEventWinner(Arrays.asList(
        new Game("John"), new Game("Zach"), new Game("Zach"),
        new Game("Chad"), new Game("John"), new Game("Jack")
)));
// output John

If it is needed to define the winner the person who achieved the maximum number of wins earlier, another loop-based solution should be used:

public static String getEventWinnerFirst(List<Game> games) {
    Map<String, Integer> winMap = new HashMap<>();
    String resultWinner = null;
    int max = -1;
    for (Game game : games) {
        String winner = game.getWinner();
        int tempSum = winMap.merge(winner, 1, Integer::sum);
        if (max < tempSum) {
            resultWinner = winner;
            max = tempSum;
        }
    }
    return resultWinner;
}

For the same input data, the output will be Zach because he occurred twice in the list earlier than John.


Update 2

It may be possible to find the earliest achiever of the max result using Stream but a temporary map needs to be created to store the number of wins:

public static String getEventWinner(List<String> games) {
    Map<String, Integer> tmp = new HashMap<>();
    return games.stream()
        .map(Game::getWinner) // Stream<String>
        .map(winner -> Map.entry(winner, tmp.merge(winner, 1, Integer::sum))) // store sum in tmp map
        .collect(Collectors.maxBy(Map.Entry.comparingByValue()))
        .map(Map.Entry::getKey) // the key - winner name
        .orElse(null);
}

Upvotes: 3

Gonen I
Gonen I

Reputation: 6107

Stream APIs are great but can be a bit cryptic for the uninitiated. I find that non streaming code is often more readable.

Here is a solution in that spirit:

  List<String> winners = Arrays.asList("a","b","c","c","b","b");
  Map<String,Integer> entries = new HashMap<>();
  String mostFrequent=null;
  int mostFrequentCount=0;
  for (String winner : winners) {
      Integer count = entries.get(winner);
      if (count == null) count = 0;
      entries.put(winner, count+1);
      if (count>=mostFrequentCount)
      {
          mostFrequentCount=count;
          mostFrequent=winner;
      }
  }
  System.out.println("Most frequent = " + mostFrequent + " # of wins =  " + mostFrequentCount );
  

Upvotes: 0

Related Questions