2017-08-06 83 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));