java获取列表中最常见的元素

webghufk  于 2021-06-27  发布在  Java
关注(0)|答案(10)|浏览(310)

java或guava是否有返回列表中最常见元素的内容?

List<BigDecimal> listOfNumbers=  new ArrayList<BigDecimal>();

[1,3,4,3,4,3,2,3,3,3,3,3]
返回3

ikfrs5lh

ikfrs5lh1#

如果你愿意使用谷歌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);

现在,排序 copies 按其值递减。

uqzxnwby

uqzxnwby2#

也许用Guava最简单的解决方法是

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();
  }
}

这是一个完整的解决方案,而且比我看到讨论的其他替代方案要短。

agxfikkp

agxfikkp3#

下面是louis答案的扩展,支持多个元素具有相同的最大出现次数的情况:

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;
}
kg7wmglp

kg7wmglp4#

下面是一个纯Java8解决方案(注意:不要使用这个,请参见下文):

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);

另一种解决方案是,根据元素的频率将元素收集到一个Map中,然后找到具有最大值的条目并返回其键(基本上与arshajii的答案相同,使用java8编写):

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);

更新:如果最常见的元素不止一个,并且您希望将所有元素都包含在一个集合中,我建议使用两种方法:
方法a:将原始集合收集到以键为元素、值为其出现次数的Map后,获取具有最大值的条目,并过滤具有与我们找到的最大值(if)相等的值的Map条目。像这样:

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());

方法b:将原始集合收集到以键作为元素、值作为其出现次数的Map后,将此Map转换为以键作为出现次数、值作为具有此出现次数的元素列表的新Map。然后用一个比较键的自定义比较器找到这个Map的max元素,并得到这个条目的值。这样地:

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());
1mrurvl1

1mrurvl15#

这很容易自己实现:

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

如果要处理存在多个最频繁元素的情况,可以扫描列表一次以确定最频繁元素出现的次数,然后再次扫描列表,将这些元素放入一个集合中并返回该集合。

zfycwa2u

zfycwa2u6#

查找集合中最常用的项目:

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);
}
lhcgjxsq

lhcgjxsq7#

我们可以轻松地在一次迭代中完成:

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;
}
34gzjxbg

34gzjxbg8#

Guava提供了一种方法,将有助于,虽然它的效率低于路易斯的解决方案。

BigDecimal mostCommon = 
    Multisets.copyHighestCountFirst(ImmutableMultiset.copyOf(listOfNumbers))
        .iterator().next();
wfsdck30

wfsdck309#

在统计学中,这被称为“模式”。普通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);

由此产生:

3=8

乔λ 是一个支持 mode() 在溪流上。以下程序:

System.out.println(
    Seq.of(1, 3, 4, 3, 4, 3, 2, 3, 3, 3, 3, 3)
       .mode()
);

产量:

Optional[3]

为了简单起见,我省略了使用 BigDecimal . 不过,解决办法是一样的。
(免责声明:我为joo背后的公司工作λ)

r6hnlfcb

r6hnlfcb10#

实现这一点的经典方法是对列表进行排序,然后逐一进行处理:

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;
}

这比使用散列来计数要节省一些空间,因为它可以对数组进行适当的排序。您可以将其放入泛型类并用t替换biginteger,或者只使用object代替biginteger。

相关问题