如何使用lambda从列表及其出现的位置中找到最大的数字?

时间:2019-04-06 21:39:48

标签: java lambda java-stream

请在下面找到一个代码,该代码对流中数字出现的次数进行计数,并返回一个映射,该映射以数字作为键,并将值作为其在整个流中的出现:

Map<Integer, Long> collect = Stream.of(1, 2, 3, 4, 4, 55555, 12)
                .collect(groupingBy(Function.identity(), counting()));

如何将生成的地图限制为最大数量(或平局时为最大数量)?

4 个答案:

答案 0 :(得分:0)

我假设您想获得流中最频繁的号码。因此,您可以使用TreeMap收集所有结果并获取最后一个条目的列表:

Map<Integer, Long> collect = Stream.of(1, 2, 3, 4, 4, 55555, 12)
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
        .entrySet().stream()
        .collect(Collectors.groupingBy(Map.Entry::getValue, TreeMap::new, Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)))
        .lastEntry().getValue();

这将返回包含数字和频率的条目列表。在您的情况下,它会打印:

{4=2}

如果您只想获取最大次数的出现次数,则可以使用以下方法:

Map.Entry<Integer, Long> collect = Stream.of(1, 2, 3, 4, 4, 55555, 12)
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
        .entrySet().stream()
        .max(Map.Entry.comparingByKey())
        .orElse(null);

哪些印刷品:

55555=1

在最后一种情况下,您只有一个(最大值)返回条目。您也可以使用TreeMap获得最大值,应该具有更好的性能。

答案 1 :(得分:0)

我希望有人能提出一个更简单的解决方案:

  const startTime = new Date();
  if (await page.$(nextPageSelector) !== null) {
    await page.$eval(nextPageSelector, link => link.click());
  }

  await page.waitForSelector(mainSelector);

  const currentTime = new Date();
  let diff = currentTime - startTime;
  diff /= 1000;
  fs.appendFileSync('logs.txt', `${diff}\n`, (err) => {});

因此,首先将它们收集到您已经拥有的同一张地图上。然后按值对它们进行排序;然后迭代该结果,并仅 那些刚开始并与它们的值匹配的结果。

想法是,由于这些已经按值进行了排序: List<Entry<Integer, Long>> list = List.of(3, 3, 4, 4, 5, 5, 1) .stream() .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) .entrySet() .stream() .sorted(Map.Entry.<Integer, Long>comparingByValue().reversed()) .collect(Collectors.toList()); Map<Integer, Long> result = new HashMap<>(); Iterator<Entry<Integer, Long>> iter = list.iterator(); Entry<Integer, Long> left; Entry<Integer, Long> right = null; while (iter.hasNext()) { left = iter.next(); if (right == null) { result.put(left.getKey(), left.getValue()); } if (iter.hasNext() && (right = iter.next()).getValue().longValue() == left.getValue()) { result.put(right.getKey(), right.getValue()); } else { break; } } -只要重复3 = 2; 4 = 2; 5 = 2; 1 = 1,我们就需要迭代,只要没有这样的匹配,就完成(因为对它们进行了排序,因此跟在2之后的任何元素都只会更小)。

答案 2 :(得分:0)

看看这个简单的例子:

public static void getMeNumbersWithHighestFrequence3(int[] numbers, int howMany) {

    Map<Integer, Long> collect = IntStream.of(numbers).boxed().collect(groupingBy(Function.identity(), TreeMap::new, counting())).descendingMap().entrySet().stream()
            .limit(howMany)
            .collect(TreeMap::new, (map, entry) -> map.put(entry.getKey(), entry.getValue()), Map::putAll);

}

您还可以通过放置过滤器值以某种方式搜索它们,它将接受键值大于该值的所有条目,例如:

  public static void getMeNumbersWithHighestFrequenceByFilterNumber(int[] numbers, int value) {

        Map<Integer, Long> collect = IntStream.of(numbers).boxed().collect(groupingBy(Function.identity(), TreeMap::new, counting())).descendingMap().headMap(value, true);

    }

  

简单用法:


public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4, 4, 55555, 12};
        getMeNumbersWithHighestFrequence(numbers, 5);
    }

答案 3 :(得分:0)

我建议您使用https://stackoverflow.com/a/10384890/1684254或我的图书馆StreamEx中定义的MoreCollectors

int result = Stream.of(1, 2, 12, 3, 4, 4, 55555, 12)
    .collect(MoreCollectors.maxAll(MoreCollectors.countingInt()));

// map result
Map<Integer, Integer> mapResult = Stream.of(1, 2, 12, 3, 4, 4, 55555, 12)
    .collect(maxAll(groupingBy(Function.identity(), countingInt())));

因为您可能想要:1)所有最大数字的总和,或2)将它们映射到其他对象,或3)进一步。 不需要,也不应只为一种特定的用户情况编写这种特定的代码。 (如果您想知道如何实现它,只需下载库的源代码或反编译类。它们在Apache License v2上发布)

更新。实际上,我认为问您是否在谈论数字可能是错误的问题,因为传统的for-loop比使用lambda更简单和有效:

int[] nums = {1, 2, 12, 3, 4, 4, 55555, 12, 55555};
int[] result = {Integer.MIN_VALUE, 0}; // [0] is the largest number if [1] (occurrence) is bigger than 0.

for (int num : nums) {
  if (num > result[0]) {
    result[0] = num;
    result[1] = 1;
  } else if (num == result[0]) {
    result[1]++;
  }
}

System.out.println(result[0] + ": " + result[1]);

如果您必须使用Stream / Lambdas:

int[] result = IntStream.of(nums).collect(() -> new int[] {Integer.MIN_VALUE, 0}, (a, num) -> {
  if (num > a[0]) {
    a[0] = num;
    a[1] = 1;
  } else if (num == a[0]) {
    a[1]++;
  }
}, (a1, a2) -> {
  if (a1[0] == a2[0]) {
    a1[1] += a2[1];
  } else if (a1[0] < a2[0]) {
    a1[1] = a2[1];
  }
});

System.out.println(result[0] + ": " + result[1]);