2016-04-06 21 views
3

私はこの質問のタイトルをどのように表現するのか本当に分かりませんでした。ダブルループで条件付きチェックを効率的に実行するにはどうすればよいですか?

要素のリストに対して反復処理を行い、特定の条件に基づいて、その要素を新しいリストに追加したいとしましょう。

ここでは、アイテムが最初のリスト(2番目のリストには存在しない)に排他的かどうかを基本的にチェックしたいメソッドを作成します。今私は、この特定の愚かたとえば、あなたがセットを使用してこの問題を解決することができることを知っているが、私はちょうどこのようなものは、私が唯一の現在のItem iを追加したいので、ここで

public List<Item> newItems(List<Item> items, List<Item> otherItems) { 
    List<Item> newItems = new ArrayList<>(); 

    for (Item i: items) { 
     for (Item j: otherItems) { 
      if (i.equals(j)) 
       //Missing code 
     } 
     newItems.add(i); 
    } 

    return newItems; 
} 

をポップアップしまう場合を説明しようとしていますotherItemsの1つの項目と等しくない場合はnewItemsになります。私の最初のインパルスは、//Missing Codeと書かれているbreak;ですが、それは最初のループから抜けるだけで、iからnewItemsへの追加を妨げません。

ブール変数を使用してifステートメントの真偽を常にチェックし、2番目のループの最後にある真理値に基づいてItem inewItemsに追加するという正しい解決方法を知っています。これは次のようになります:

for (Item i: items) { 
    boolean check = true; 

    for (Item j: otherItems) { 
     if (i.equals(j)) 
      check = false; 
      break; //To avoid unnecessary iterations 
    } 

    if (check) 
     newItems.add(i); 
} 

これは非常に嵩張っていてもかなり冗長です。これを行うより効率的でエレガントな方法がありますか?

+0

はソートされたリストですか? – AchmadJP

+0

@AchmadJPこれはArrayListなので、各要素はリスト内の別個の位置にあります。 –

答えて

3

私が正しくあなたの質問を理解していれば、あなたが存在している項目を除くitemsからアイテムを集めているリストを作成する必要がありますitemsotherItemsの両方にあります。そうならば、あなたはList#removeAll()するだけでそれを行うことができます。

public List<Item> newItems(List<Item> items, List<Item> otherItems) { 
    List<Item> res = new ArrayList<>(items); // create a copy of items 
    res.removeAll(otherItems);    // remove items presented in otherItems 
    return res; 
} 

を流れ、フィルタ(S)とコレクタを、項目を除外使用するために、他の条件(複数可)がある場合は、次のように:

return items.stream() 
      .filter(i -> !otherItems.contains(i)) 
      .filter(/* another condition */) 
      .collect(Collectors.toList()); 
+0

実際に私がやっていたこの例では、特定の条件に基づいてアクションを実行する一般的な方法を探していました。あなたが提案する解決策は、この例に関連しているだけです –

+0

ありがとう、私はそれを調べます! –

1

ええと、リストが既にソートされている場合。私が思うより速い解決策は、バイナリサーチを使うことです。シーケンシャルサーチよりも高速です。

for(Item i: items){ 
    if(Collections.binarySearch(otherItems, i) < 0){ 
     newItems.add(i); 
    } 
} 
1

私がしている場合は、私はこのようにします:

for(Item i: items){ 
    if(!otherItems.contains(i)){ 
     newItems.add(i); 
    } 
} 
+0

ArrayListに '.contains'を使用できますか?私はそれがセットで有効な構文だと思った。 –

+1

公式の文書で見ることができる:https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#contains(java.lang.Object ) – Wakachopo

0

まあ、あなたは何かのようにすることができます。

CollectionUtils.removeAll(collection1, collections2); 

この方法は、同様にあなたにコレクションを返します。これと私はあなたがフォーカスダウン彼らに逆さまを与え、すべてのアイテムがあなたの条件を満たした後、どのされていないものを削除することを想定できると思います他のケースで

https://commons.apache.org/proper/commons-collections/javadocs/api-release/org/apache/commons/collections4/CollectionUtils.html

1

。ネストされたループに代わるものとして

public List<Item> newItems(List<Item> items, List<Item> otherItems) { 
List<Item> newItems = new ArrayList<>(items); 

for (Item i: items) { 
    for (Item j: otherItems) { 
     if (i.equals(j)){ 
      newItems.remove(i) 
      break; 
    } 
} 
return newItems; 
} 
1

、Javaの8で、次の操作を実行するためにStreams APIを使用することができます:この例では

public List<Item> newItems(List<Item> items, List<Item> otherItems) { 
    return items.stream() 
       .filter(i -> !otherItems.contains(i)) 
       .collect(Collectors.toList()); 
} 
2

WakachopoAchmadJPで指摘したように、あなたが行うことができますcontainsまたはbinarySearchを使用して説明します。今、あなたが言うことを、これらの操作は、単なる例示であり、あなたは異なる条件ウェルは何もないかもしれない同じパターンを使用してからあなたを停止しますが、今、あなたは特定のメソッドを自分記述する必要があります。

for(Item i: items) { 
    if(!hasMatchingCondition(i, otherItems) { 
     newItems.add(i); 
    } 
} 

static boolean hasMatchingCondition(Item i, List<Item> list) { 
    for(Item j: list) { 
     if(whatever condition regarding i and j) { 
      return true; 
     } 
    } 
    return false; 
} 

クリーンと短期を回路。

あなたはラベル付きステートメントを使用して、単一の方法で同じことを行うことができ、すなわち

outer: for(Item i: items) { 
    for(Item j: list) { 
     if(whatever condition regarding i and j) { 
      continue outer; 
     } 
    } 
    newItems.add(i); 
} 

が、ステートメントが落胆機能一部の開発者によると、おそらくもっと重要なのは、あなたがhasMatchingCondition方法のための別の用途を見出すことができると考えられているラベルどこかに。

関連する問題