2017-09-10 44 views
2

我有一些數據從MySQL中選擇。然後我想格式化它。 數據只是想:java8流列表<Map>如何隱藏分組後的地圖通過

var json = [ 
 
    { 
 
    "date": "2016-01", 
 
    "number": "1", 
 
    "code": "420000", 
 
    "type": "false" 
 
    }, 
 
    { 
 
    "date": "2016-01", 
 
    "number": "2", 
 
    "code": "440000", 
 
    "type": "false" 
 
    }, 
 
    { 
 
    "date": "2016-02", 
 
    "number": "3", 
 
    "code": "420000", 
 
    "type": "false" 
 
    }, 
 
    { 
 
    "date": "2016-03", 
 
    "number": "4", 
 
    "code": "420000", 
 
    "type": "true" 
 
    }, 
 
    { 
 
    "date": "2016-03", 
 
    "number": "5", 
 
    "code": "410000", 
 
    "type": "false" 
 
    }, 
 
    { 
 
    "date": "2016-03", 
 
    "number": "6", 
 
    "code": "440000", 
 
    "type": "true" 
 
    }, 
 
    { 
 
    "date": "2016-04", 
 
    "number": "7", 
 
    "code": "420000", 
 
    "type": "false" 
 
    }, 
 
    { 
 
    "date": "2016-04", 
 
    "number": "8", 
 
    "code": "440000", 
 
    "type": "false" 
 
    } 
 
]; 
 
console.log(json);

我想groupingBy日期,並partitioningBy,並reducing地圖。 後格式的數據就像

var json = { 
 
    "2016-01": { 
 
    "false": { 
 
     "420000": "1", 
 
     "440000": "2" 
 
    } 
 
    }, 
 
    "2016-02": { 
 
    "false": { 
 
     "420000": "3" 
 
    } 
 
    }, 
 
    "2016-03": { 
 
    "false": { 
 
     "410000": "5" 
 
    }, 
 
    "true": { 
 
     "420000": "4", 
 
     "440000": "6" 
 
    } 
 
    }, 
 
    "2016-04": { 
 
    "false": { 
 
     "420000": "7", 
 
     "440000": "8" 
 
    } 
 
    } 
 
}; 
 
console.log(json);

我編碼java8流

public static void main(String[] args) { 
    List<Map<String, String>> postmans = new ArrayList<>(); 

    // "420000" : post area code, "false": just paper(without goods) 
    postmans.add(createMap("2016-01", "1", "420000", "false")); 
    postmans.add(createMap("2016-01", "2", "440000", "false")); 
    postmans.add(createMap("2016-02", "3", "420000", "false")); 
    postmans.add(createMap("2016-03", "4", "420000", "true")); 
    postmans.add(createMap("2016-03", "5", "410000", "false")); 
    postmans.add(createMap("2016-03", "6", "440000", "true")); 
    postmans.add(createMap("2016-04", "7", "420000", "false")); 
    postmans.add(createMap("2016-04", "8", "440000", "false")); 

    // before, I use fastjson Library 
    System.out.println(JSONObject.toJSONString(postmans)); 


    Map<String, Map<Boolean, Map>> data = postmans.stream() 
      .collect(Collectors.groupingBy(d -> d.get("date"), TreeMap::new, 
        Collectors.partitioningBy(d-> d.get("type").equals("true"), 
          Collectors.reducing(new HashMap(), (d1, d2)->{ 
           Object code = d2.get("code"); 
           Object number = d2.get("number"); 
           // I think bug in reducing 
           d1.put(code, number); 
           return d1; 
          })))); 
    // after, I use fastjson Library 
    System.out.println(JSONObject.toJSONString(data)); 

} 

private static Map<String,String> createMap(String date, String number, String code, String type){ 
    Map<String, String> map = new HashMap<>(); 
    map.put("date", date); 
    map.put("number", number); 
    map.put("code", code); 
    map.put("type", type); 
    return map; 
} 

,但真正的結果是

var json = { 
 
    "2016-01": { 
 
    "false": { 
 
     "410000": "5", 
 
     "420000": "7", 
 
     "440000": "8" 
 
    }, 
 
    "true": { 
 
     "410000": "5", 
 
     "420000": "7", 
 
     "440000": "8" 
 
    } 
 
    }, 
 
    "2016-02": { 
 
    "false": { 
 
     "410000": "5", 
 
     "420000": "7", 
 
     "440000": "8" 
 
    }, 
 
    "true": { 
 
     "410000": "5", 
 
     "420000": "7", 
 
     "440000": "8" 
 
    } 
 
    }, 
 
    "2016-03": { 
 
    "false": { 
 
     "410000": "5", 
 
     "420000": "7", 
 
     "440000": "8" 
 
    }, 
 
    "true": { 
 
     "410000": "5", 
 
     "420000": "7", 
 
     "440000": "8" 
 
    } 
 
    }, 
 
    "2016-04": { 
 
    "false": { 
 
     "410000": "5", 
 
     "420000": "7", 
 
     "440000": "8" 
 
    }, 
 
    "true": { 
 
     "410000": "5", 
 
     "420000": "7", 
 
     "440000": "8" 
 
    } 
 
    } 
 
}; 
 
console.log(json);

我覺得這個bug的原因是reduing。當partitioningBy得到新的List <Map>時,舊的d1仍然存在。

我只想把partitioningBy的結果,每個List <Map>壓縮到一個map,我可以保證它的key (code)是唯一的。

我很抱歉代碼太長,我的英文很差。謝謝你的幫助!

+1

您的縮小單位始終是完全相同的'HashMap'實例。你應該有不同的地圖來減少每個分支的操作​​。 –

回答

1

這裏有兩個主要的錯誤。 Collectors.reducing,因爲這是一個減少,需要返回一個新的實例的所有時間,基本上第二是你的邏輯是有缺陷的:

Map<String, Map<Boolean, Map<String, String>>> data = postmans.stream() 
      .collect(Collectors.groupingBy(
        d -> d.get("date"), 
        TreeMap::new, 
        Collectors.partitioningBy(
          d -> d.get("type").equals("true"), 
          Collectors.reducing(
            new HashMap<>(), 
            (left, right) -> { 

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

             String leftCode = left.get("code"); 
             String leftNumber = left.get("number"); 

             if (leftCode == null) { 
              map.putAll(left); 
             } else { 
              map.put(leftCode, leftNumber); 
             } 

             String rightCode = right.get("code"); 
             String rightNumber = right.get("number"); 

             map.put(rightCode, rightNumber); 

             return map; 

            })))); 

您還可以存儲DateString,做TreeMap::new的問題 - 這基本上排序Strings s,這可能不是你想要的排序。一般來說,將所有東西都作爲String的整個方法使代碼難以閱讀。

+0

你可以添加執行過程嗎?你爲什麼要新的'HashMap'和'putAll(left)'? – Ahaochan

+1

@Ahaochan執行過程非常簡單,如果您在合併之前和之後(在return map之前)打印左側和右側地圖,您可以自己找到它。第二部分基本上是'reduce'和'collect'之間的差異 - 減少需要隨時返回一個新實例,你可以在這裏閱讀更多:https://stackoverflow.com/questions/22577197/java-8-streams -collect-vs-reduce – Eugene

+0

謝謝!我有一個Java值和引用的簡單錯誤。 'identity'只創建一次,每次'List'時恢復。我的代碼中的錯誤是修改'identity',導致身份恢復失敗。 – Ahaochan

相關問題