2010-07-07 46 views
2

如果我有一個ArrayList<Double> dblListPredicate<Double> IS_EVEN我能夠使用從dblList刪除所有偶數元素:如何使用謂詞從已轉換的集合中刪除元素?

Collections2.filter(dblList, IS_EVEN).clear() 

如果dblList不過是一個轉型的像

dblList = Lists.transform(intList, TO_DOUBLE) 

因此這不工作任何更多的變換列表是不可變的:-)

任何解決方案?

回答

0

可能:

Collection<Double> odds = Collections2.filter(dblList, Predicates.not(IS_EVEN)); 

dblList = Lists.newArrayList(Lists.transform(intList, TO_DOUBLE)); 
Collections2.filter(dblList, IS_EVEN).clear(); 
+0

這很好,如果我只對結果感興趣。相反,我真的想間接修改原始集合。 所以很明顯,轉換後的List不支持像set()這樣的修改操作。 但是我不清楚爲什麼transform()和filter()本身支持remove操作,但兩者的組合都不支持它。我即將消除這... 但它不是 – Ditz 2010-07-07 20:11:16

0

只要你不需要中間集合,然後你可以使用Predicates.compose()來創建一個謂詞,第一變換該項目,然後評估變形項目上的謂詞。

例如,假設我有一個List <雙>從中我想刪除所有項目,其中整數部分是偶數。我已經有一個函數< Double,整數>,它給了我整數部分,以及一個謂詞<整數>告訴我它是否是偶數。

我可以用它們來得到一個新的謂詞,INTEGER_PART_IS_EVEN

Predicate<Double> INTEGER_PART_IS_EVEN = Predicates.compose(IS_EVEN, DOUBLE_TO_INTEGER); 
Collections2.filter(dblList, INTEGER_PART_IS_EVEN).clear();
+0

對於這種嘗試,我需要原始(或至少轉換)列表。不幸的是(在我的情況下)它被封裝,我不想公開它。我可能會引入回調以在內部執行刪除操作,但這隻能是某種解決方法。 取而代之,我喜歡在級聯轉換和過濾收藏集上看到工作的Iterator.remove()操作。 – Ditz 2010-07-07 22:07:45

0

一些嘗試後,我想我已經找到了:)

final ArrayList<Integer> ints = Lists.newArrayList(1, 2, 3, 4, 5); 
Iterables.removeIf(Iterables.transform(ints, intoDouble()), even()); 
System.out.println(ints); 

[1,3,5] 
+0

但我不知道爲什麼 Iterables.removeIf(Lists.transform(ints,intoDouble()),even()); crash ... 我在番石榴討論組 – 2010-07-08 08:16:13

2

Lists.transform()接受List和有益返回結果是RandomAccess列表。 Iterables.transform()只接受一個I​​terable,並且結果不是RandomAccess。最後,Iterables.removeIf(並且據我所知,這是Iterables中唯一的一個)在給定的參數是RandomAccess的情況下具有優化,其中的要點是使得算法是線性的而不是二次的。想想如果你有一個大的ArrayList(而不是一個ArrayDeque - 應該更受歡迎)會發生什麼,並保持從開始時刪除元素,直到它空。

但優化不取決於迭代器remove(),而是List.set(),這在轉換的列表中不可能受支持。如果要修復這個問題,我們需要另一個標記接口來表示「可選的set()實際上起作用」。

所以選項你是:

  • 呼叫Iterables.removeIf()版本,並運行一個二次算法(也沒什麼關係,如果你的列表很小或刪除幾個要素)
  • 將列表複製到另一個支持所有可選操作的列表中,然後調用Iterables.removeIf()。
+0

發表問題嗨dimitris,清楚的解釋,但我沒有看到任何Lists.removeIf() – 2010-07-08 09:00:15

+0

對不起,錯字,意味着Iterables.removeIf()。 – 2010-07-08 09:25:33

+0

在第二種選擇中,副本不會導致較低的性能? – 2010-07-08 10:17:41

0

我沒有解決方案,而是發現某種問題Iterables.removeIf()Lists.TransformingRandomAccessList的組合。

轉換後的列表實現RandomAccess,因此Iterables.removeIf()代表Iterables.removeIfFromRandomAccessList()這取決於不受支持的List.set()操作。 然而調用Iterators.removeIf()會成功,因爲remove()操作由Lists.TransformingRandomAccessList支持。

見:Iterables:147

結論的instanceof RandomAccess的不保證List.set()。

增加: 在特殊情況下調用removeIfFromRandomAccessList()甚至作品: 當且僅當元件以擦除形式的緊湊組在列表的尾部或所有的元件由謂詞覆蓋。

1

以下方法應該可行,但我還沒有嘗試過。

Collection<Double> dblCollection = 
    Collections.checkedCollection(dblList, Double.class); 
Collections2.filter(dblCollection, IS_EVEN).clear(); 

checkCollection()方法生成未實現List的列表視圖。 [它會更清晰,但更詳細,創建一個ForwardingCollection。]然後Collections2.filter()不會調用不支持的set()方法。

庫代碼可以變得更健壯。 Iterables.removeIf()可以生成一個組合的謂詞,正如Michael D所建議的,當傳遞一個變換列表時。但是,我們之前決定不添加這種特殊情況的邏輯來使代碼複雜化。

相關問題