如何使用java 8流和功能接口过滤掉这个列表?

时间:2014-07-26 18:56:16

标签: java arrays lambda java-8

如果我有这样的数组列表(伪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]};

如何使用Java 8流和lambdas过滤此列表,以便获得:

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

2 个答案:

答案 0 :(得分:3)

你使用&#34; distinct&#34;建议使用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());

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

另一种方法是使用某种有状态的收集器,但这会在任何后续处理开始之前存储整个结果列表,这是你想要避免的。

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

(信用:技术从this answer被盗。)

答案 1 :(得分:1)

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对其进行分组,则从那里开始。您可以调用values方法,该方法返回列表集Collection<List<Point>>。然后,您可以调用此Collection的流,并从每个列表中获取第一个值,该值根据您的规范按降序版本号进行排序,因此它应该是最高版本号。从那里你要做的就是将它们收集到一个列表,数组或任何你认为必要的东西中,然后根据需要进行分配。

这里唯一的问题是它们是无序打印的。这应该是一个简单的解决方案。