2017-05-05 10 views
3

私は解決できないような2つの問題があります。最初の1つは、ユーザーが渡すことができる1-nのネストされたグループが存在する場所で動的なネストされたグループ化を行う方法が必要です。Java 8ネストされたグループ化

第2の問題は、入れ子ではなく連結します。

私の例入力は次のようになります。キーがマップ内にネストされたマップではなく、連結されている

{ 
    "10.0.1.1user": [ 
    { 
     "uid": "tiger", 
     "ip": "10.0.1.1", 
     "group": "user" 
    }, 
    { 
     "uid": "woods", 
     "ip": "10.0.1.1", 
     "group": "user" 
    } 
    ], 
    "10.0.1.0admin": [ 
    "uid": "root", 
    "ip": "10.0.1.0", 
    "group": "admin" 
    ] 
} 

お知らせ:

List<Map<String, String>> fakeData = new LinkedList<>(); 
    Map<String, String> data1 = new HashMap<>(); 
    data1.put("ip","10.0.1.0"); 
    data1.put("uid","root"); 
    data1.put("group","admin"); 
    fakeData.add(data1); 

    Map<String, String> data2 = new HashMap<>(); 
    data2.put("ip","10.0.1.1"); 
    data2.put("uid","tiger"); 
    data2.put("group","user"); 
    fakeData.add(data2); 

    Map<String, String> data3 = new HashMap<>(); 
    data3.put("ip","10.0.1.1"); 
    data3.put("uid","woods"); 
    data3.put("group","user"); 
    fakeData.add(data3); 

最終結果はマップキーの連結を持っています。

私はそれがどんな運なしで動的にすることができgroupingbyを作成しようとしています:

fakeData.stream() 
       .collect(groupingBy(map -> map.get("ip"), 
         groupingBy(map -> map.get("uuid"), 
           ... nested "n" times))); 

は、これは私が実装しようとしているインターフェースである約

public Map<String, List<Map<String, String>>> doGrouping(List<String> columns, 
                List<Map<String, String>> data); 
+1

実装しようとしているメソッドの入出力を完全に理解していません。出力タイプに "n"個のネストされたグループが含まれているようには見えません。あなたのサンプルデータで 'doGrouping'をどのように呼び出すつもりか、期待される出力はどうなるでしょうか? – 4castle

+0

'doGrouping'の' columns'引数に 'N'要素が含まれている場合、' N'要素のそれぞれでネストされたグループを作成する必要がありますか?そして、各グループのキーを入れ子にするのではなく連結したいと思っていますか? –

+2

出力またはインターフェイスにnレベルのネストを示唆するものは表示されません。トップレベルで複数のキーでグループ化しているようです。 – shmosel

答えて

5

は、以下のことを試してみてください。

public Map<String, List<Map<String, String>>> doGrouping(
     List<String> columns, 
     List<Map<String, String>> data) { 

    return data.stream() 
     .collect(Collectors.groupingBy(
      elem -> columns.stream() 
       .map(elem::get) 
       .collect(Collectors.joining()))); 
} 

まず、私はマップのリストである、dataをストリーミング。私はただちに、Collectors.groupingByを使ってリストのマップにストリームを収集しました。このキーはストリームの各要素に対して計算されています。

キーの計算は難しい部分でした。このために、私はcolumnsの指定されたリストをストリーミングし、これらの各列をストリームの要素の対応する値に変換しました。私はこれをメソッドで行い、elem::mapをマッピング関数として渡しました。最後に、この内部ストリームをCollectors.joiningを使用して単一の文字列に集めました。このストリームは、ストリームの各要素を効率的な方法で最後の文字列に連結します。

編集:columnsのすべての要素がdataのマップ要素のキーとして存在する場合、上のコードはうまく機能します。以下のより安全な使用にするために:

return data.stream() 
    .collect(Collectors.groupingBy(
     elem -> columns.stream() 
      .map(elem::get) 
      .filter(Objects::nonNull) 
      .collect(Collectors.joining()))); 

このバージョンでは、一部のマップ要素がcolumnsリストで指定されたキーが含まれていない場合に発生する可能性のあるストリームからnullの要素を除外します。

+2

'c - > elem.getOrDefault(c、" ")'を使うこともできます。 – shmosel

+0

@shmosel正しいですが、空の文字列をターミナル操作に伝播させるのは正しいですか?この場合、空の文字列を結合すると最終的に結合された文字列には影響がありませんが、コレクション中にフィルタリングされる要素をストリームに保持するのが最善ではないと感じました。 –

+1

パーフェクト!フェデリコは本当にありがとう。それがトリックでした。 – Xuan

2

わかりませんストリームを使用して、しかし、あなたが普通のJavaの方法を好む場合、それはずっと簡単です。 ここで問題を正しく理解している場合は、作成する方法があります。あなたはそれをより速くするために微調整する必要があるかもしれません。

public Map<String, List<Map<String, String>>> doGrouping(List<String> columns, List<Map<String, String>> data) { 
    Map<String, List<Map<String, String>>> output = new HashMap<>(); 
    for (Map<String, String> map : data) { 
     String key = ""; 
     for(String column : columns) key += "".equals(key) ? (map.get(column)) : (":" + map.get(column)); 
     output.computeIfAbsent(key, k -> Arrays.asList(map)); 
    } 
    return output; 
} 

テスト:

doGrouping(Arrays.asList("ip", "group"), fakeData) 
>> {10.0.1.1:user=[{uid=tiger, ip=10.0.1.1, group=user}, {uid=woods, ip=10.0.1.1, group=user}], 10.0.1.0:admin=[{uid=root, ip=10.0.1.0, group=admin}]} 

doGrouping(Arrays.asList("group"), fakeData) 
>> {admin=[{uid=root, ip=10.0.1.0, group=admin}], user=[{uid=tiger, ip=10.0.1.1, group=user}, {uid=woods, ip=10.0.1.1, group=user}]} 
+2

Upvoted、これは正しい答えです。ちょっとした提案... 'if/else'ブロックを' output.computeIfAbsent(key、k - >新しいArrayList <>())。add(map) 'に変更することができます。 –

+0

それは良い提案であるようです。今すぐ通勤して、しばらくしてからもう一度試してみてください。 –

関連する問題