2017-08-09 23 views
-2

私は項目date、id、およびactionを持つItemのクラスを持っています。私の場合、私は古いアイテムのリストと古いアイテムと新しいアイテムを含む別のリストを持っているので、古いアイテムを除外したいので、私はそれらを気にしません。たとえば、新しいアイテムを繰り返し、古いアイテムリストに属していないアイテムだけを使用します。 (forループ付きリストのJavaストリームの相違

が、それは次のようになりますが、私はその複雑な条件を避けるために、あなたのItemクラスでそれをすべての

List<Item> filteredList = new ArrayList<>(); 
    for (Item item : newList) { 
     for (Item oldItem : oldList) { 
      if (!item.getDate().equals(oldItem.getDate()) && !item.getId().equals(oldItem.getId()) && !item.getAction().equals(oldItem.getAction())) { 
       filteredList.add(item); 
      } 
     } 
    } 
+5

「誰もがいつも」ストリームを使用しようとしているのはなぜですか?ストリームがどのように機能し、どのような機能が提供されるかを見ると、ループをストリームに移行するための努力は何も示していません。 – luk2302

+4

他のリストから項目を削除する場合は、常に 'list.removeAll(otherList)'を使用できます。あなたのアイテムがequalsメソッドで適切に比較できることを確認してください。 – Pshemo

答えて

3

まず、私はequalsメソッドを実装することをお勧め機能的な方法を書き換えるしたいです私は正しいかどうかわからない、BTW)。

さらに検索を効率化するには、古いリストの要素をHashSetに入れて、一定の時間の検索を可能にします。これには、equalshashCodeの両方をItemクラスに上書きする必要があります。

最後のコードは次のようになります。

List<Item> filteredList = 
    newList.stream() 
      .filter(i -> !oldList.contains(i)) // oldList should be replaced with a HashSet 
               // for better performance 
      .collect(Collectors.toList()); 

HashSetで:

Set<Item> oldSet = new HashSet<>(oldList); 
List<Item> filteredList = 
    newList.stream() 
      .filter(i -> !oldSet.contains(i)) 
      .collect(Collectors.toList()); 

をあなたの条件について:

if (!item.getDate().equals(oldItem.getDate()) && !item.getId().equals(oldItem.getId()) && !item.getAction().equals(oldItem.getAction())) 

それは、間違って表示される2つの項目が異なった場合以来IDは同じ日付(またはアクション)を持つため、テストに失敗します。

私はあなたが書くためのものと考えている:

if (!item.getDate().equals(oldItem.getDate()) || !item.getId().equals(oldItem.getId()) || !item.getAction().equals(oldItem.getAction())) 

これは、彼らが3つの特性の少なくとも1つが異なる場合2つのアイテムが互いに異なると考えられていることを意味します。あなたは正しく項目を比較できるように

2

まず第一に、あなたはList年代.contains() methodを使用している場合、たとえば、それが必要とされるであろう、あなたのItemクラスで(同様と.hashCode()equals()メソッドを実装する必要があります。

.contains()メソッドを使用すると、現在のアイテムがoldListに存在するかどうかをテストし、その結果に基づいてアイテムをフィルタすることができます。

のJava 8で、あなたのコードは次のようになります。

List<Item> result = newList.stream()     
     .filter(line -> !oldList.contains(line))  
     .collect(Collectors.toList()); 

注:あなただけListを使用してこれを実装することができますようstreamの使用は、ここで本当に必要でないことを

注意メソッド、たとえば.retainAll()を使用すると、より良い方法でnewListをフィルタリングできます。

+0

equalsを実装する場合は、hashCodeも実装する必要があることに注意してください。 –

+1

@ Absurd-Mindそれを指摘していただきありがとうございます。もちろん、 '.hashCode'は' .equals() 'と一緒に実装する必要があります。 –

1

このタスクにはストリームは必要ありません。ただ、正確に何をしたいんList.removeAll方法、使用します。

oldList.removeAll(newList); 

をこれは、要素が等しいかどうかを比較することができ、削除するように、equals()メソッドを実装するItemクラスが必要です。

あなたの元oldListを変異させたくない場合は、新しいリストを作成し、それから要素を削除することができます。それを行うには

List<Item> filteredList = new ArrayList<>(oldList); 
filteredList.removeAll(newList); 

別の複数の機能性っぽい方法が使用することによりますCollection.removeIf方法:

oldList.removeIf(item -> newList.contains(item)); 

それとも:

oldList.removeIf(newList::contains); 

equals()メソッドを実装するには、依然としてItemクラスが必要です。しかし、List.containsnewListを走査して、oldListの各項目がそれに属しているかどうかをチェックする必要があるので、非効率的でもあります。より効率的なアプローチはHashSetを使用することであろう。

そして
Set<Item> newSet = new HashSet<>(newList); 

、上記のようremoveIfを使用:

oldList.removeIf(newSet::contains); 

このアプローチはequals()方法を実施するItemクラスを必要とするだけでなく、hashCodeのみならずこのメソッドは、等価性に関してObjectクラス契約に準拠しなければなりません。

関連する問題