AnsonH
AnsonH

Reputation: 3256

Find the most frequent element in a 2D String array & its number of occurrences

I would like to ask how can I find the most frequent element in a 2D String array and also the number of occurrences this element has in Java?

More specifically:

public static void mostFrequentElement(String[][] data) {
    // What should I write here?
}
String[][] data = {
        {"apple", "orange", "orange"},
        {"grape", "orange", "melon"},
};

mostFrequentElement(data);
// The function prints "orange 3" in the console
// This is because "orange" is the most frequent
// element in the data array and it showed up 3 times

I tried using HashMap, but I got confused with it since I'm a beginner to Java. Thank you very much!

Upvotes: 0

Views: 971

Answers (5)

Abra
Abra

Reputation: 20914

/*
 * import java.util.Arrays;
 * import java.util.Comparator;
 * import java.util.Map;
 * import java.util.function.Function;
 * import java.util.stream.Collectors;
 */
public static void mostFrequentElement(String[][] data) {
    Arrays.stream(data) // returns Stream<String[]>
            // returns Stream<String>
            .flatMap(row -> Arrays.stream(row))
            // returns Map<String, Long>
            .collect(Collectors.groupingBy(
                    Function.identity(), Collectors.counting()))
            // returns Set<Map.Entry<String, Long>>
            .entrySet()
            // returns Stream<Map.Entry<String, Long>>
            .stream()
            // returns Optional<Entry<String, Long>>
            .max(Comparator.comparing(Map.Entry::getValue))
            .ifPresent(System.out::println);
}

For your sample data, above code displays...

orange=3

Upvotes: 2

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79065

Java Stream API makes it easier to do in a succinct way:

import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        String[][] data = {
                {"apple", "orange", "orange"},
                {"grape", "orange", "melon"},
        };

        Map.Entry<String, Long> entryWithTheMaxCount =
                // Get a Stream<String[]> out of the String[][]
                Arrays.stream(data)
                        // Flatten the Stream<String[]> to Stream<String>
                        .flatMap(Arrays::stream)
                        // Collect the flattened Stream into
                        // a frequency Map<String, Integer>
                        .collect(Collectors.groupingBy(
                                Function.identity(), Collectors.counting()))
                        // The following function calls are required
                        // only to get the entry with max count
                        .entrySet()
                        .stream()
                        .max(Map.Entry.comparingByValue())
                        .get();

        System.out.println(entryWithTheMaxCount);
    }
}

Output:

orange=3

Upvotes: 1

Sankeeth Ganeswaran
Sankeeth Ganeswaran

Reputation: 477

This looks like a job for a HashMap. By looping through the 2d array and adding elements to the map or incrementing their mapped values by 1 if they're already in the map, we can keep track of the number of occurrences for each elements. And by also creating a max variable to hold the highest number of occurrences so far and updating it in the loop, by the end of the loop it will hold the element with the highest number of occurrences. Here is my implementation, but feel free to check out the Java Documentation for hashmaps, as it's quite helpful.

public static void mostFrequentElement(String[][] data) {
    //keeps track of maximum occurrences
    int max = 0;
    String maxElem = "";
    //mapping the strings to the number of occurrences
    HashMap<String, Integer> map = new HashMap<String, Integer>();
    //looping through the 2d array
    for (int i = 0; i < data.length; i++) {
        for (int j = 0; j < data[i].length; j++) {
            // if current element is already in
            // the map, increment its occurrence by 1
            if (map.containsKey(data[i][j])) {
                map.put(data[i][j], map.get(data[i][j]) + 1);
            }
            //if not, add it to the map with 1 occurrence
            else {
                map.put(data[i][j], 1);
            }
            // if the current element's occurrences is
            // bigger than max so far, set it to the max
            if (map.get(data[i][j]) > max) {
                max = map.get(data[i][j]);
                maxElem = data[i][j];
            }
        }
    }
    //print out the maximum after looping through all the elements
    System.out.println(maxElem + " " + max);
}

Upvotes: 1

user14838237
user14838237

Reputation:

It depends on the task conditions, the first approach is faster, and the last one is slower:

String[][] data = {
        {"apple", "orange", "orange"},
        {"grape", "orange", "melon"}};

Stream<String> stream = Arrays.stream(data).flatMap(Arrays::stream);
  1. If you want to filter certain elements and get count of them:

    Long count = stream.filter(str -> str.equals("orange")).count();
    
    System.out.println(count); // 3
    
  2. If you want to get an array of distinct elements:

    String[] distinct = stream.distinct().toArray(String[]::new);
    
    System.out.println(Arrays.toString(distinct));
    // [apple, orange, grape, melon]
    

    Or you can use HashSet:

    HashSet<String> set = stream.collect(Collectors.toCollection(HashSet::new));
    
    System.out.println(set);
    // [orange, apple, grape, melon]
    
  3. If you want to collect a map of duplicates:

    Map<String, Long> duplicates = stream.collect(
            Collectors.groupingBy(Function.identity(), Collectors.counting()));
    
    System.out.println(duplicates);
    // {orange=3, apple=1, grape=1, melon=1}
    

See also: How to find duplicate elements in array in effective way?

Upvotes: 1

Saeed Alizadeh
Saeed Alizadeh

Reputation: 1467

This solution has 3 steps:

  1. find the frequency of elements in each dimension of array
  2. aggregate result of each dimension
  3. find the max
public class Main {
  public static void main(String[] args) {
    String[][] data = {
      {"apple", "orange", "orange"},
      {"grape", "orange", "melon"},
    };
    HashMap<String, Long> finalHashMap = new HashMap<>();
    for (String[] row : data) {
      HashMap<String, Long> oneDimensionResult =
          Arrays.asList(row).stream()
              .collect(
                  Collectors.groupingBy(Function.identity(), HashMap::new, Collectors.counting()));
      for (String s : oneDimensionResult.keySet()) {
        if (finalHashMap.containsKey(s)) {
          Long count = finalHashMap.get(s);
          finalHashMap.put(s, oneDimensionResult.get(s) + count);
        } else {
          finalHashMap.put(s, oneDimensionResult.get(s));
        }
      }
    }
    Entry<String, Long> maxEntry = null;
    for (Entry<String, Long> entry : finalHashMap.entrySet()) {
      if (maxEntry == null || entry.getValue().compareTo(maxEntry.getValue()) > 0) {
        maxEntry = entry;
      }
    }
    System.out.println(maxEntry.getKey() + ":" + maxEntry.getValue());
  }
}

Upvotes: 1

Related Questions