Java-获取列表中最常见的元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19031213/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java-get most common element in a list
提问by Doc Holiday
Does Java or Guava have something that will return most common element in a list?
Java 或 Guava 是否有返回列表中最常见元素的东西?
List<BigDecimal> listOfNumbers= new ArrayList<BigDecimal>();
[1,3,4,3,4,3,2,3,3,3,3,3]
[1,3,4,3,4,3,2,3,3,3,3,3]
return 3
返回 3
采纳答案by arshajii
This is fairly easy to implement yourself:
这很容易自己实现:
public static <T> T mostCommon(List<T> list) {
Map<T, Integer> map = new HashMap<>();
for (T t : list) {
Integer val = map.get(t);
map.put(t, val == null ? 1 : val + 1);
}
Entry<T, Integer> max = null;
for (Entry<T, Integer> e : map.entrySet()) {
if (max == null || e.getValue() > max.getValue())
max = e;
}
return max.getKey();
}
List<Integer> list = Arrays.asList(1,3,4,3,4,3,2,3,3,3,3,3);
System.out.println(mostCommon(list));
3
If you want to handle cases where there's more then one most frequent element, you can scan the list once to determine how many times the most frequent element(s) occur, and then scan the list again, put those elements in a set and return that.
如果您想处理不止一个最频繁元素的情况,您可以扫描列表一次以确定最频繁的元素出现的次数,然后再次扫描列表,将这些元素放入一个集合中并返回那。
回答by Alcanzar
The classic way to do this is to sort the list and then work through them one by one:
执行此操作的经典方法是对列表进行排序,然后一一处理它们:
public static BigInteger findMostCommon(List<BigInteger> list) {
Collections.sort(list);
BigInteger mostCommon = null;
BigInteger last = null;
int mostCount = 0;
int lastCount = 0;
for (BigInteger x : list) {
if (x.equals(last)) {
lastCount++;
} else if (lastCount > mostCount) {
mostCount = lastCount;
mostCommon = last;
}
last = x;
}
return mostCommon;
}
This is a bit more space efficient than using a hash to tally counts since it sorts the array in place. You could toss this into a generics class and replace BigInteger with T, or just use Object in place of BigInteger.
这比使用散列来统计计数更节省空间,因为它对数组进行了排序。您可以将其放入泛型类并用 T 替换 BigInteger,或者仅使用 Object 代替 BigInteger。
回答by Eric Jablow
If you are willing to use Google Guava, you can use its MultiSet
classes:
如果你愿意使用 Google Guava,你可以使用它的MultiSet
类:
MultiSet<BigNumber> numbers = HashMultiSet.create();
numberSet.addAll(list);
Set<MultiSet.Entry<BigNumber>> pairs = numbers.emtrySet();
Set<MultiSet.Entry<BigNumber>> copies = new HashSet<MultiSet.Entry<BigNumber>>(pairs);
Now, sort copies
by its values descending.
现在,copies
按其值降序排序。
回答by Louis Wasserman
Probably the simplest solution with Guava looks like
可能最简单的番石榴解决方案看起来像
Multiset<BigDecimal> multiset = HashMultiset.create(listOfNumbers);
BigDecimal maxElement = null;
int maxCount = 0;
for (Multiset.Entry<BigDecimal> entry : multiset.entrySet()) {
if (entry.getCount() > maxCount) {
maxElement = entry.getElement();
maxCount = entry.getCount();
}
}
That's a complete solution, and shorter than the other alternatives I see discussed.
这是一个完整的解决方案,比我看到讨论的其他替代方案更短。
回答by Jared Levy
回答by a.b.d
Here is an extension of Louis' answer that support the case where there is multiple elements with same max occurrence count:
这是路易斯回答的扩展,支持存在多个具有相同最大出现次数的元素的情况:
private <T> List<T> getMostFrequentElements(List<T> list) {
Multiset<T> multiset = HashMultiset.create(list);
List<T> mostFrequents = new ArrayList<>();
int maxCount = 0;
for (Multiset.Entry<T> entry : multiset.entrySet()) {
if (entry.getCount() > maxCount) {
maxCount = entry.getCount();
mostFrequents.clear();
mostFrequents.add(entry.getElement());
} else if (entry.getCount() == maxCount) {
mostFrequents.add(entry.getElement());
}
}
return mostFrequents;
}
回答by Utku ?zdemir
Here is a pure Java 8solution (note: do not use this one, see below):
这是一个纯Java 8解决方案(注意:不要使用这个,见下文):
List<Integer> theList = Arrays.asList(1, 3, 4, 3, 4, 3, 2, 3, 3, 3, 3, 3);
Integer maxOccurredElement = theList.stream()
.reduce(BinaryOperator.maxBy((o1, o2) -> Collections.frequency(theList, o1) -
Collections.frequency(theList, o2))).orElse(null);
System.out.println(maxOccurredElement);
Another solution, by collecting the elements to a map by their frequency, then finding the entry with max value and returning its key (basically the same solution on arshajii's answer, written using Java 8):
另一种解决方案,通过按频率将元素收集到映射,然后找到具有最大值的条目并返回其键(与使用 Java 8 编写的arshajii's answer基本相同的解决方案):
Integer maxVal = theList.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet().stream().max((o1, o2) -> o1.getValue().compareTo(o2.getValue()))
.map(Map.Entry::getKey).orElse(null);
Update:If the most frequent elements are more than one, and you want to get all of them in a collection, I propose two methods:
更新:如果出现频率最高的元素不止一个,并且您想将所有元素都放在一个集合中,我提出两种方法:
Method A:After collecting the original collection to a map with keys as elements and values as their number of occurrences, getting the entry with the maximum value and filtering the map entries with value equal to this max value (if) we found. Something like this:
方法A:将原始集合收集到一个以key为元素,value为出现次数的map后,得到最大值的条目,过滤掉我们找到的值等于这个最大值的map条目(if)。像这样的东西:
Map<Integer, Long> elementCountMap = theList.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
List<Integer> result = elementCountMap.values().stream()
.max(Long::compareTo).map(maxValue -> elementCountMap.entrySet().stream()
.filter(entry -> maxValue.equals(entry.getValue())).map(Map.Entry::getKey).collect(Collectors.toList()))
.orElse(Collections.emptyList());
Method B:After collecting the original collection to a map with keys as elements and values as their number of occurrences, transforming this map into a new map with keys as number of occurences, values as a list of elements with this number of occurences. And then finding the max element of this map with a custom comparator which compares the keys, and getting the value of this entry. Like this:
方法B:将原始集合收集到一个以key为元素,value为出现次数的map后,将该map转换为一个新的map,以key为出现次数,value为一个具有该出现次数的元素列表。然后使用自定义比较器查找此映射的最大元素,该比较器比较键,并获取此条目的值。像这样:
List<Integer> result = theList.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet().stream()
.collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList())))
.entrySet().stream().max((o1, o2) -> o1.getKey().compareTo(o2.getKey())).map(Map.Entry::getValue)
.orElse(Collections.emptyList());
回答by Lukas Eder
In statistics, this is called the "mode". A vanilla Java 8 solution looks like this:
在统计学中,这被称为“模式”。一个普通的 Java 8 解决方案如下所示:
Stream.of(1, 3, 4, 3, 4, 3, 2, 3, 3, 3, 3, 3)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.max(Comparator.comparing(Entry::getValue))
.ifPresent(System.out::println);
Which yields:
其中产生:
3=8
jOOλis a library that supports mode()
on streams. The following program:
System.out.println(
Seq.of(1, 3, 4, 3, 4, 3, 2, 3, 3, 3, 3, 3)
.mode()
);
Yields:
产量:
Optional[3]
For simplicity's sake, I omitted using BigDecimal
. The solution would be the same, though.
为简单起见,我省略了使用BigDecimal
. 不过,解决方案是一样的。
(disclaimer: I work for the company behind jOOλ)
(免责声明:我为 jOOλ 背后的公司工作)
回答by Sandeep Sharda
We can do in only one iteration with ease:
我们可以轻松地在一次迭代中完成:
public static Integer mostFrequent(List<Integer> list) {
if (list == null || list.isEmpty())
return null;
Map<Integer, Integer> counterMap = new HashMap<Integer, Integer>();
Integer maxValue = 0;
Integer mostFrequentValue = null;
for(Integer valueAsKey : list) {
Integer counter = counterMap.get(valueAsKey);
counterMap.put(valueAsKey, counter == null ? 1 : counter + 1);
counter = counterMap.get(valueAsKey);
if (counter > maxValue) {
maxValue = counter;
mostFrequentValue = valueAsKey;
}
}
return mostFrequentValue;
}
回答by nejckorasa
Find most frequent item in collection:
查找集合中出现频率最高的项目:
private <V> V findMostFrequentItem(final Collection<V> items)
{
return items.stream()
.filter(Objects::nonNull)
.collect(Collectors.groupingBy(Functions.identity(), Collectors.counting())).entrySet().stream()
.max(Comparator.comparing(Entry::getValue))
.map(Entry::getKey)
.orElse(null);
}