2017-08-06 60 views
0

我最近有这个问题。 这是我的代码如何过滤一个列表中的列表?

for(int i=1; i<=repeticiones;i++){ 
    posiblesComunes.removeIf(p->!periodos.get(i).contains(p)); 
} 

periodos是List(Set(String)),posiblesComunes是Set(String)

我需要做的就是只有在所有的设置(字符串)在periodos的字符串。 我试图做的是使用的,但我得到了一个消息:

我在一个封闭的范围内定义的局部变量必须是最后的或有效的最终

有没有什么办法来解决这个问题?或者另一种方式来获得这些元素? 谢谢!

编辑: 只是一个例子

periodos = {("1-1-16","6-12-16"),("1-1-16","2-8-15"),("3-7-08","1-1-16")} 

我需要得到的是“1-1-16”的一个共同点。

EDIT2:

periodosComunes的范例(for循环):

periodosComunes = ("1-1-16","6-2-16") 
+1

而不是指定的集合类型,它会更有助于提供它们的定义。 –

+2

你可以使用一个临时变量:'final int _i = i;' – shmosel

+2

或者你可以做'periodos.forEach(posiblesComunes :: retainAll);' – shmosel

回答

2

如何:

Set<String> periodosComunes = Set.of("1-1-16","6-2-16"); 
List<Set<String>> periodos = List.of(
    Set.of("1-1-16","6-12-16"), 
    Set.of("1-1-16","2-8-15"), 
    Set.of("3-7-08","1-1-16") 
); 

List<String> result = periodosComunes.stream() 
    .filter(x -> periodos.stream() 
     .allMatch(y -> y.contains(x)) 
) 
    .collect(Collectors.toList()); 

// result = [1-1-16] 

我以前收集的文字从Java 9救了我一些打字,但这与解决方案无关。

+2

当您收集到一个'Set'时,'distinct()'调用已经过时。但无论如何,你的'白名单'包含了所有集合的联合,而不是交集,所以'whitelist :: contains'只要它在任何集合中就可以接受一个元素,而不是集合中的所有集合。 。 – Holger

+0

@Holger我错过了这个要求;相应更新了我的答案。它实际上使事情变得更简单。 –

+0

非常感谢!我不敢相信我用for循环制造一团糟D: – user7519940

1

并非所有列表都为迭代器提供了删除其项目的能力;但是,如果您选择正确的列表,则会将其内置到Iterator界面中。

Iterator i = list.iterator(); 
while (i.hasNext()) { 
    if (i.next().equals(bad)) { 
     i.remove(); 
    } 
} 

解决方案的简单性是足够的,你可能会考虑跳过流为基础的方法,而不像某些种类的修饰,去除Iterator不会抛出ConcurrentModificationException

+0

这很“简单”,因为你方便省略了“坏”来自哪里。流或不流,只要你压扁另一个列表,你最终得到我的建议。更不用说不可变性等了。 –

+0

@AbhijitSarkar Bad是包含您要过滤的值的对象。实际上,你可以将任何东西放入条件语句中,'i.remove()'将起作用。如果无法确定如何确定他们想要移除的内容,那么这是一个更大的问题,无法通过代码解决。 –

+0

我明白你的代码中有什么'bad'。我质疑使用'Iterator'的说法无论如何比使用'Stream'更简单或更好,主要是因为它是2017. –

3

您不能从lambda表达式访问本地变量i,因为它在循环过程中被修改。最简单的解决方法是捕捉i当前值在另一个一成不变的变量:

for(int i=1; i<=repeticiones;i++) { 
    int finalI = i; 
    posiblesComunes.removeIf(p -> !periodos.get(finalI).contains(p)); 
} 

注意的for-each循环不存在这个问题的变量:

for(Set<String> set: periodos.subList(1, repeticiones)) 
    posiblesComunes.removeIf(p -> !set.contains(p)); 

但最终,您在这里过度使用Java 8功能。这个操作可以与原来的集合API从Java 2来完成:

for(Set<String> set: periodos.subList(1, repeticiones)) 
    posiblesComunes.retainAll(set); 

这也将与原来的循环工作:

for(int i=1; i<=repeticiones; i++) 
    posiblesComunes.retainAll(periodos.get(i)); 

在这里,你还可以添加一个快捷方式,为设定永不,所以如果没有共同的元素,你可以停止一旦设定成了空

for(int i=1; i<=repeticiones && !posiblesComunes.isEmpty(); i++) 
    posiblesComunes.retainAll(periodos.get(i)); 
+0

很好的解释。你总是给我们一个常见问题的惊喜。 –

0

这应该工作(如果我没有理解好你的需求):

import java.util.stream.*; 
import java.util.*; 
public class P { 

    public static void main(String []a) { 
    // Init. 
    Set<String> periodosComunes = new HashSet<>(); periodosComunes.add("1-1-16"); periodosComunes.add("6-2-16"); 
    Set<String> s1 = new HashSet<>(); s1.add("1-1-16"); s1.add("6-12-16"); 
    Set<String> s2 = new HashSet<>(); s2.add("1-1-16"); s2.add("2-8-15"); 
    Set<String> s3 = new HashSet<>(); s3.add("1-1-16"); s3.add("3-7-08"); 
    List<Set<String>> periodos = new ArrayList<>(); periodos.add(s1); periodos.add(s2); periodos.add(s3); 

    // Computes the set of commons... 
    Set<String> r = periodosComunes.stream().filter(p->periodos.stream().allMatch(s->s.contains(p))).collect(Collectors.toSet()); 
    System.out.println(r);             
    } 
} 

最初在periodosCommunes中的一组常见周期在r。现在,您可以使用一套在必要时对原设定删除相应的:

periodosComunes.removeIf(s->!r.contains(s));