如何用java8流和函数接口过滤掉这个列表



如果我有这样的数组列表(伪java代码(:

请注意,valsSorted列表将始终按x[0]asc和x[1]desc顺序排序。

List valsSorted = {[1 5][1 4][1 3][2 1][3 2][3 1][4 2][4 1][5 1][6 2][6 1]};

我如何用Java8流和Lambda过滤这个列表,以便获得:

result  = {[1 5][2 1][3 2][4 2][5 1][6 2]}

数组的第一项(x[0](是ID,第二项是版本号。因此,规则是返回具有最高版本的所有不同ID。

如果我使用for循环,下面的代码就可以了:

 ArrayList<int[]> result= new ArrayList();
    int keep = -1;
    for (int[] x : valsSorted) {
        int id = x[0];
        int version = x[1];
        if(keep == id)   continue;
        keep = id;
        result.add(x);
    }

使用单词"distinct"建议使用distinct()流操作。不幸的是,该操作被硬连接为使用流元素的equals()方法,这对数组没有用处。处理此问题的一种方法是将数组包装在一个包装器对象中,该包装器对象具有您正在寻找的相等语义:

class Wrapper {
    final int[] array;
    Wrapper(int[] array) { this.array = array; }
    int[] getArray() { return array; }
    @Override
    public boolean equals(Object other) {
        if (! (other instanceof Wrapper))
            return false;
        else
            return this.array[0] == ((Wrapper)other).array[0];
    }
    @Override
    public int hashCode() { ... }
}

然后在distinct()之前包装您的对象,并在之后打开它

List<int[]> valsDistinct =
    valsSorted.stream()
        .map(Wrapper::new)
        .distinct()
        .map(Wrapper::getArray)
        .collect(toList());

这会对数据进行一次传递,但它会为每个值生成一个垃圾对象。这也依赖于按顺序处理的流元素,因为您想要第一个。

另一种方法是使用某种有状态收集器,但这最终会在任何后续处理开始之前存储整个结果列表,而您曾说过要避免这种情况。

可能值得考虑将数据元素设置为实际的类,而不是两个元素数组。通过这种方式,您可以提供一个合理的平等概念,还可以使值具有可比性,以便您可以轻松地对它们进行排序。

(来源:从这个答案中窃取的技术。(

class Test{
     List<Point> valsSorted = Arrays.asList(new Point(1,5),
          new Point(1,4),
          new Point(1,3),
          new Point(2,1),
          new Point(3,2),
          new Point(3,1),
          new Point(4,2),
          new Point(4,1),
          new Point(5,1),
          new Point(6,2),
          new Point(6,1));
     public Test(){
        List<Point> c = valsSorted.stream()
              .collect(Collectors.groupingBy(Point::getX))
              .values()
              .stream()
              .map(j -> j.get(0))
              .collect(Collectors.toList());
        for(int i=0; i < c.size(); i++){
            System.out.println(c.get(i));
        }
    }
    public static void main(String []args){
        Test t = new Test()
    }
}

我决定使用点类,并将ID字段表示为x,将版本号表示为Y。因此,如果从那里创建流并按ID对其进行分组,则可以调用返回列表集合Collection<List<Point>>的values方法。然后,您可以调用该集合的流,并从每个列表中获取第一个值,根据您的规范,该值按版本号降序排列,因此它应该是最高的版本号。从那里,你所要做的就是将它们收集到一个列表、数组或任何你认为必要的东西中,并根据需要进行分配。

这里唯一的问题是它们打印出了问题。不过,这应该是一个简单的解决方案。

最新更新