7

私は

TreeMap resMap new TreeMap<String, Map<String, String>>(); 

値に既知のペアが含まれているエントリのみをフィルタリングして保持したいと思います。たとえば、('mike' => 'jordan') としましょう。以下のようなループを回避します。

含まれているライブラリ apache.commons および google.common にフィルター メソッドがありますか (おそらくループも実行されますが、少なくとも冗長ではありません)。

for (Entry<String, TreeMap<String, String>> el : resMap.entrySet()){
    if (el.getValue().get("mike").equals("jordan")){
        //
    }
}
4

6 に答える 6

11

Guava とPredicateインターフェースからフィルターを使用できます。

Predicate<T> yourFilter = new Predicate<T>() {
    public boolean apply(T o) {
        // your filter
    }
};

したがって、簡単な例は次のようになります。

Predicate<Integer> evenFilter = new Predicate<Integer>() {
    public boolean apply(Integer i) {
        return (i % 2 == 0);
    }
};

Map<Integer, Integer> map = new HashMap<Integer, Integer>();

Map<Integer, Integer> evenMap = Maps.filterValues(map, evenFilter);
于 2012-06-22T16:42:53.457 に答える
4

クライアント コードにフィルター/ループの使用を強制するのではなく、必要なものをクラスの API に組み込みます。

public class MyClass {

    private TreeMap resMap new TreeMap<String, Map<String, String>>();

    public void filter(String key, String value) {
        // Some impl here. Either your loop or the guava approach
    }
}

ところで、ループを使用する場合は、次のように変更することを検討してください。

for (Iterator<Map.Entry<String, TreeMap<String, String>>> i = resMap.entrySet().iterator(); i.hasNext();) {
    Map.Entry<String, TreeMap<String, String>> entry = i.next();
    if (value.equals(entry.getValue().get(key))) {
        i.remove();
    }
}

ループの変更点は次のとおりです。

  • NPE を回避するために等号の順序を変更
  • iteratorエントリの直接削除を許可するために使用

クラスがなくても、ユーティリティ クラスの静的メソッドに簡単にまとめることができます。ここで、ネストされたマップを操作するために簡単にパラメーター化することもできます。

public static <K1, K2, V> void filter(Map<K1, Map<K2, V>> map, K2 key, V value) {
    // Some impl here
}

静的メソッドのグアバ以外の実装は次のとおりです。

for (Iterator<Map.Entry<K1, Map<K2, V>>> i = map.entrySet().iterator(); i.hasNext();) {
    Map.Entry<K1, Map<K2, V>> entry = i.next();
    if (value.equals(entry.getValue().get(key))) {
        i.remove();
    }
}
于 2012-06-22T17:03:06.277 に答える
0

2 つの例を次に示します。両方とも、値のプロパティの一致に基づいてキーを出力します。

private static void printMatchingEntriesUsingALoop(Map<String, Map<String, String>> resMap, String key, String value) {
    for (Map.Entry<String, Map<String, String>> entry : resMap.entrySet())
        if (value.equals(entry.getValue().get(key)))
            System.out.println(entry.getKey());
}

private static void printMatchingEntriesUsingGuava(Map<String, Map<String, String>> resMap, final String key, final String value) {
    Predicate<Map<String, String>> keyValueMatch = 
    new Predicate<Map<String, String>>() {
        @Override
        public boolean apply(@Nullable Map<String, String> stringStringMap) {
            return value.equals(stringStringMap.get(key));
        }
    };

    Maps.EntryTransformer<String, Map<String, String>, Void> printKeys = 
    new Maps.EntryTransformer<String, Map<String, String>, Void>() {
        @Override
        public Void transformEntry(@Nullable String s, 
                 @Nullable Map<String, String> stringStringMap) {
            System.out.println(s);
            return null;
        }
    };

    Maps.transformEntries(Maps.filterValues(resMap, keyValueMatch), printKeys);
}

public static void main(String... args) {
    Map<String, Map<String, String>> resMap = new TreeMap<String, Map<String, String>>();
    printMatchingEntriesUsingALoop(resMap, "first", "mike");
    printMatchingEntriesUsingGuava(resMap, "first", "mike");
}

1 つはループを使用し、もう 1 つは Guava を使用します。

前者の方がパフォーマンスは優れていますが、どちらが理解しやすく維持しやすいかを実際に判断する必要があります。

@missingfaktor からのいくつかの提案。あなた自身の判断を使わなければなりませんが、彼はいくつかの問題をうまく強調しました.

  1. コードの重複が多い。
  2. 特例扱い。
  3. より循環的な複雑さ。
  4. 最初の 3 つの箇条書きの結果として、エラーの可能性が高くなります。
  5. コードをたどるのが難しい。

あなたがこのソフトウェアをサポートしなければならない新しい開発者だと想像してください。どちらに直面したいですか?

于 2012-06-22T18:21:48.347 に答える
0

GuavaPredicates and Functionsを見てください。

于 2012-06-22T16:35:12.963 に答える
0

Java 8 とストリームを使用してマップをフィルタリングできます。このプロセスの最初のステップは、 を使用してストリームに変換することですentrySet().stream()。これにより、 が得られますStream<Map.Entry<String, TreeMap<String, String>>。その後、 を使用filter(...)してリストをフィルタリングできます。フィルター処理を行う場合、受信値をフィルター結果に含める必要がある場合は true を返す必要があります。結果をフィルタリングした後、 foreach を使用して最終結果をループできます。

最終結果は次のようになります。

resMap.entrySet().stream()
      .filter(e -> el.getValue().get("mike").equals("jordan"))
      .foreach(e -> {
        // Do something with your entry here
      });
于 2016-03-14T18:25:41.567 に答える