2017-04-07 18 views
3

このコードをどのようにして単一のラムダ式に単純化できますか?アイデアはマップのリストがあり、キーのフィルターを使用してマップの新しいリストを作成したいと考えています。この例では、キー "x"と "z"のみを保持するように再マップします。Java 8ストリームを使用したマップのリストの処理

Map<String, String> m0 = new LinkedHashMap<>(); 
    m0.put("x", "123"); 
    m0.put("y", "456"); 
    m0.put("z", "789"); 

    Map<String, String> m1 = new LinkedHashMap<>(); 
    m1.put("x", "000"); 
    m1.put("y", "111"); 
    m1.put("z", "222"); 

    List<Map> l = new ArrayList<>(Arrays.asList(m0, m1)); 
    List<Map> tx = new ArrayList<>(); 
    for(Map<String, String> m : l) { 
     Map<String, String> filtered = m.entrySet() 
       .stream() 
       .filter(map -> map.getKey().equals("x") || map.getKey().equals("z")) 
       .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue())); 
     tx.add(filtered); 
    } 
    System.err.println("l: " + l); 
    System.err.println("tx: " + tx); 

出力:入力キーがxzない場合

List<Map<String, String>> l = Arrays.asList(m0, m1); 

l.forEach(map -> { 
    map.entrySet().removeIf(e -> !e.getKey().equals("x") && !e.getKey().equals("z")); 
}); 

それは単にすべてのMap<String, String>にすべてのマッピングを削除します。

l: [{x=123, y=456, z=789}, {x=000, y=111, z=222}] 
    tx: [{x=123, z=789}, {x=000, z=222}] 

答えて

7

もちろん、操作全体を1つのストリーム操作に変換することができます。あなたが実際のキーのごく少数を持っていながら、それは、フィルタに対する各マップの各キーをチェックするよう

// no need to copy a List (result of Array.asList) to an ArrayList, by the way 
List<Map<String, String>> l = Arrays.asList(m0, m1); 

List<Map<String, String>> tx = l.stream().map(m -> m.entrySet().stream() 
     .filter(map -> map.getKey().equals("x") || map.getKey().equals("z")) 
     .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()))) 
    .collect(Collectors.toList()); 

しかしMapとフィルタリングの上にそのストリーミングに注意してくださいは、線形時間複雑さと操作です保持したいしたがって、ここでは、より大規模なマップの方がはるかに簡単で効率的です(大きなマップの場合)。マップごとに4つのルックアップしか実行しません。それが気になる場合は、2つのルックアップに減らすこともできますが、一定の係数は、時間の複雑さには無関係です。一定の時間になります。マップに一定の時間がある場合は、HashMapのようになります。例えばTreeMapのようなO(log(n))のルックアップ時間の複雑なマップであっても、マップがサンプルコードの3つのマッピングよりも大きい場合、これはリニアスキャンより効率的です。

2

あなたはこのような何かを試すことができます。

編集:Radiodefの同等の、より短い方法を利用する必要があります。

List<Map<String, String>> l = Arrays.asList(m0, m1); 

l.forEach(map -> map.keySet().retainAll(Arrays.asList("x", "z")); 
+1

このスタイルでは、さらに小さなバージョンはmap.keySet()。retainAll(Arrays.asList( "x"、 "z")) 'のようなものを使うことになります。 (編集:しかし、補足として、コレクターとのOPのコードは、これらが全く同じではないようにコピーを作成します。) – Radiodef

+0

@Radiodefああ、良いキャッチ! –

+0

'removeIf'ベースの解でさえ、' Entry'で '.getKey()'を2回呼び出すのではなく、 '.keySet()'を最初に使用して表現形式から利益を得ます: 'l.forEach(map - > "k.equals(" x ")&&!k.equals(" z "))); map.keySet()。removeIf(k - >! – Holger

0

次のコードを試してみてください(私はdesiredKeys用リスト宣言):

public class Main { 
    public static void main(String[] args) { 
     Map<String, String> m0 = new HashMap<>(); 
     m0.put("x", "123"); 
     m0.put("y", "456"); 
     m0.put("z", "789"); 

     Map<String, String> m1 = new HashMap<>(); 
     m1.put("x", "000"); 
     m1.put("y", "111"); 
     m1.put("z", "222"); 

     List<Map<String, String>> l = new ArrayList<>(Arrays.asList(m0, m1)); 

     List<String> desiredKeys = Lists.newArrayList("x", "z"); 

     List<Map<String, String>> transformed = l.stream().map(map -> map.entrySet().stream() 
       .filter(e -> desiredKeys.stream().anyMatch(k -> k.equals(e.getKey()))) 
       .collect(Collectors.toMap(e -> e.getKey(), p -> p.getValue()))).filter(m -> !m.isEmpty()).collect(Collectors.toList()); 

     System.err.println(l); 
     System.err.println(transformed); 
    } 
} 
0

はこれを試してみてくださいを、それが動作するはずです:

Map<String, String> m0 = new HashMap<>(); 
     m0.put("x", "123"); 
     m0.put("y", "456"); 
     m0.put("z", "789"); 

     Map<String, String> m1 = new HashMap<>(); 
     m1.put("x", "000"); 
     m1.put("y", "111"); 
     m0.put("z", "222"); 

     List<Map> l = new ArrayList<>(Arrays.asList(m0, m1)); 
     List<Map> transformed = new ArrayList<Map>() ; 
     l.stream().map(map -> { 
      Set<String> keys = map.keySet() ; 
      Map<String, String> newMap = new HashMap<>(); 
      for(String key : keys){ 
       if(key.equals("x")|| key.equals("z")) 
        newMap.put(key, map.get(key).toString()) ; 
      } 
      return newMap ; 
     }).forEach(map -> transformed.add(map)); 

     System.out.println(transformed); 
0

方法について:

tx = StreamEx.of(l) 
       .map(m -> EntryStream.of(m).filterKeys(k -> k.equals("x") || k.equals("z")).toMap()) 
       .toList(); 

によってStreamEx

関連する問題