Reputation: 3256
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
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
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
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
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);
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
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]
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
Reputation: 1467
This solution has 3 steps:
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