2016-02-19 84 views
9

我很感兴趣的是确定一种方法,返回元素列表中不包含另一个列表中的元素。Java 8流。所有元素除了其他元素

例如

List<Integer> multiplesOfThree = ... // 3,6,9,12 etc 
List<Integer> evens = ... // 2,4,6,8 etc 
List<Integer> others = multiplesOfThree.except(evens) // should return a list of elements that are not in the other list 

你怎么做到这一点? 我发现这是一个有点笨重,难以阅读的方法....

multiplesOfThree.stream() 
.filter(intval -> evens.stream().noneMatch(even -> even.intValue() == intval.intValue())) 

回答

12

您可以使用Stream's filter method,传递Predicate,以确保该元素不存在evens

List<Integer> others = multiplesOfThree.stream() 
     .filter(i -> !evens.contains(i)) 
     .collect(Collectors.toList()); 

但是假设你有一个可变的List(例如ArrayList),你甚至不需要流,只是Collections's removeAll method

multiplesOfThree.removeAll(evens); 
+0

removeAll是一个优秀的解决方案。 –

5

你可以使用

multipleOfThree.stream() 
       .filter(((Predicate<Integer>) evens::contains).negate()) 

或大even名单

HashSet<Integer> evenSet = new HashSet<>(even); 
multipleOfThree.stream() 
       .filter(((Predicate<Integer>) evenSet::contains).negate()) 
1

有几个解决方案更有效。

首先,不使用流,你可以创建一个新的列表,并从它的另一个集合中删除的所有元素...

final List<Integer> multiplesOfThree = Arrays.asList(3,6,9,12); 
final List<Integer> evens = Arrays.asList(2,4,6,8,10,12); 
final List<Integer> others1 = new ArrayList<>(multiplesOfThree); 
others1.removeAll(evens); 

另一个解决方案是通过一个过滤器,通过流():

final List<Integer> others2 = multiplesOfThree 
    .stream() 
    .filter(x -> !evens.contains(x)) 
    .collect(Collectors.toList()); 

(您可能需要考虑使evens在这种情况下Set)。

最后,你可以修改上面的逻辑来表示“evens”作为一个函数,而不是所有偶数的集合。这与上述基本相同,但您不必拥有第二个集合。

final List<Integer> others3 = multiplesOfThree 
    .stream() 
    .filter(x -> x % 2 != 0) 
    .collect(Collectors.toList());