Java-查找第一个和最后两个不同的值

时间:2019-03-11 09:42:43

标签: java list java-8 java-stream

我有一个列表包含以下值,

List<Integer> data = Arrays.asList(10,10,10,9,9,9,9,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,6,6,6,6);

从那里我需要找到first(10,9)和last(6,7)不同值的总和和计数。

期望的OP:

First : Count=7, Sum=66
Last :  Count=13, Sum=87

如何使用Java 8实现此目标?

我尝试过的代码:

List<Integer> data = Arrays.asList(10,10,10,9,9,9,9,8,8,8,8,8,8,7,7,7,7,7,7,7,7,7,6,6,6,6);
List<Integer> first = data.stream().distinct().collect(Collectors.toList()); //here I am trying get first distinct values(10,10,10,9,9,9,9)
List<Integer> last = data.stream().distinct().collect(Collectors.toList());//here I am trying get last distinct values(7,7,7,7,7,7,7,7,7,6,6,6,6)
int firstSum = first.stream().mapToInt(Integer::intValue).sum();
long firstCount = first.stream().mapToInt(Integer::intValue).count();
int lastSum = last.stream().mapToInt(Integer::intValue).sum();
long lastCount = last.stream().mapToInt(Integer::intValue).count();
System.out.println("First Sum:"+firstSum+" Count"+firstCount);
System.out.println("Last Sum:"+lastSum+" Count"+lastCount);

2 个答案:

答案 0 :(得分:2)

您可以按数值对数字进行分组,并使用StreamLinkedHashMap进行计数。

List<Integer> data = Arrays.asList(10, 10, 10, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6);

Map<Integer, Long> map = data.stream().collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting()));
List<Integer> keys = new ArrayList<>(map.keySet());

int a1 = keys.get(0);
int a2 = keys.get(1);
int b1 = keys.get(keys.size() - 1);
int b2 = keys.get(keys.size() - 2);

System.out.format("First : Count=%d, Sum=%d\n", map.get(a1) + map.get(a2), a1 * map.get(a1) + a2 * map.get(a2));
System.out.format("Last : Count=%d, Sum=%d\n", map.get(b1) + map.get(b2), b1 * map.get(b1) + b2 * map.get(b2));

答案 1 :(得分:1)

使用循环。

首先在循环中找到与列表中的第一个元素不相等的第一个元素。如果未找到,则发出消息并停止。然后在循环中找到第一个元素的索引,该索引不等于这两个元素中的任何一个或列表的末尾。现在您知道前两个不同值需要覆盖的范围。现在,您可以使用流和limit进行计数和求和,或者再进行一次循环。

对最后两个不同的值执行类似的操作,只是从列表的远端开始循环。

如果列表没有很好的随机访问权限,请使用ListIterator

流不适合您的任务。至少在未排序列表中不是这样,就像您对另一个答案的评论一样。流适用于每个元素的处理不依赖于之前或之后的元素的情况。在您的任务中,计数和总和中可能包含或省略了9,具体取决于8是否在列表中。

编辑:学术练习流

我承认这对我来说是一个挑战。这是使用流的解决方案。我不建议这样做,我支持我上面所说的。它甚至可以用来显示流解决方案的复杂程度。

    List<Integer> data = Arrays.asList(10, 10, 10, 9, 9, 9, 9, 8, 8, 9, 9, 9,
            8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6);
    if (data.isEmpty()) {
        System.out.println("No elements");
    } else {
        int firstDistinct = data.get(0);
        OptionalInt secondDistinctOpt = data.stream()
                .mapToInt(Integer::intValue)
                .dropWhile(i -> i == firstDistinct)
                .findFirst();
        assert secondDistinctOpt.stream().noneMatch(sd -> sd == firstDistinct);
        Optional<IntSummaryStatistics> statsOpt = secondDistinctOpt.stream()
                .mapToObj(secondDistinct -> data.stream()
                                .mapToInt(Integer::intValue)
                                .takeWhile(i -> i == firstDistinct || i == secondDistinct)
                                .summaryStatistics())
                .findAny();
        statsOpt.ifPresentOrElse(
                stats -> System.out.println("Count = " + stats.getCount() + " Sum = "+ stats.getSum()),
                () -> System.out.println("No 2 distinct values"));
    }
  

计数= 7总和= 66

对于最后两个不同的值,您可以使用Collections.reverse反转列表并重复。

进一步的编辑:我特意从your comment中获取了您的示例列表,而不是您的问题中的列表,以证明在总和中不包括前8个后的9个计数。