在复杂的HashMap中使用StringJoiner

3

我有一个如下的Maps列表:

List<Map<String,Object>> someObjectsList = new ArrayList<Map<String,Object>>();

我正在每个 HashMap 中存储以下数据

key             value
2017-07-21      2017-07-21-07.33.28.429340
2017-07-24      2017-07-24-01.23.33.591340
2017-07-24      2017-07-24-01.23.33.492340
2017-07-21      2017-07-21-07.33.28.429540

我想遍历HashMap列表,并检查键是否与任何HashMap值的前10个字符匹配,然后我想以以下格式存储这些键和值,即使用逗号来分隔。最终目的是在一个新的HashMap中对HashMap的唯一键及其相关值(如果键与任何HashMap值的前10个字符匹配)进行分组。

key          value
2017-07-21  2017-07-21-07.33.28.429340,2017-07-21-07.33.28.429540
2017-07-24  2017-07-24-01.23.33.591340,2017-07-24-01.23.33.492340

我正在尝试使用以下Java代码,使用StringJoiner,但结果并不如预期。请问如何构建逻辑?
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;

public class SampleOne {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        List<Map<String, Object>> someObjectsList = new ArrayList<Map<String, Object>>();

        Map<String, Object> mapOne = new HashMap<String, Object>();
        mapOne.put("2017-07-21", "2017-07-21-07.33.28.429340");

        Map<String, Object> mapTwo = new HashMap<String, Object>();
        mapTwo.put("2017-07-24", "2017-07-24-01.23.33.591340");

        Map<String, Object> mapThree = new HashMap<String, Object>();
        mapThree.put("2017-07-24", "2017-07-24-01.23.33.492340");

        Map<String, Object> mapFour = new HashMap<String, Object>();
        mapFour.put("2017-07-21", "2017-07-21-07.33.28.429540");

        someObjectsList.add(mapOne);
        someObjectsList.add(mapTwo);
        someObjectsList.add(mapThree);
        someObjectsList.add(mapFour);

        for (Map map : someObjectsList) {
            StringJoiner sj = new StringJoiner(",");
            for (Object key : map.keySet()) {
                String value = ((String) map.get(key));
                String date = value.substring(0, Math.min(value.length(), 10));
                //System.out.println(str);
                //System.out.println(value);

                if(key.equals(date)) {
                    sj.add(value);
                    System.out.println(sj.toString());
                }
            }

        }

    }

}

输出:

2017-07-21-07.33.28.429340
2017-07-24-01.23.33.591340
2017-07-24-01.23.33.492340
2017-07-21-07.33.28.429540
4个回答

1

在你的代码中,你在每个映射上使用了不同的StringJoiner。因此,它正在创建一个新实例。

你可以将键保存在一个映射中。以下是示例代码: (编辑:我没有删除你的StringJoiner部分。)

public static void main(String[] args) {
        // TODO Auto-generated method stub
        List<Map<String, Object>> someObjectsList = new ArrayList<Map<String, Object>>();

        Map<String, Object> mapOne = new HashMap<String, Object>();
        mapOne.put("2017-07-21", "2017-07-21-07.33.28.429340");

        Map<String, Object> mapTwo = new HashMap<String, Object>();
        mapTwo.put("2017-07-24", "2017-07-24-01.23.33.591340");

        Map<String, Object> mapThree = new HashMap<String, Object>();
        mapThree.put("2017-07-24", "2017-07-24-01.23.33.492340");

        Map<String, Object> mapFour = new HashMap<String, Object>();
        mapFour.put("2017-07-21", "2017-07-21-07.33.28.429540");

        someObjectsList.add(mapOne);
        someObjectsList.add(mapTwo);
        someObjectsList.add(mapThree);
        someObjectsList.add(mapFour);

        Map<String, Object> outputMap = new HashMap<String, Object>();

        for (Map map : someObjectsList) {
            StringJoiner sj = new StringJoiner(",");
            for (Object key : map.keySet()) {
                String value = ((String) map.get(key));
                String date = value.substring(0, Math.min(value.length(), 10));
                //System.out.println(str);
                //System.out.println(value);

                if(key.equals(date)) {
                    sj.add(value);
                    System.out.println(sj.toString());
                    if(outputMap.containsKey(key)) {
                        String str = (String) map.get(key);
                        str = str + "," + value;
                        outputMap.put((String)key, str);
                    } else {
                        outputMap.put((String)key, value);
                    }
                }
            }
        }

        for (String map : outputMap.keySet()) {
             System.out.println(map + " " + outputMap.get(map));
        }
    }

1

你为什么使用 Object 而不是 String,并避免安全检查?话虽如此,“前10个字符”并不准确,你要看看 value 是否以 key 开头(所有键都是10个字符)。因此,在这种情况下,你可以直接执行 if (value.startsWith(key)) { ... }。如果 stringjoiner 没有填满,请不要忘记换行符。最后,你不需要一个 List,一个 Map 可以同时保存多个键。另一种方法是:

//LinkedHashMap will preserve our insertion order
Map<String, String> map = new LinkedHashMap<>();
map.put("2017-07-21", "2017-07-21-07.33.28.429340");
map.put("2017-07-24", "2017-07-24-01.23.33.591340");
//note duplicates are overwritten, but no value change here
map.put("2017-07-24", "2017-07-24-01.23.33.492340");
map.put("2017-07-21", "2017-07-21-07.33.28.429540");
//  You can also use Java 8 streams for the concatenation
//  but I left it simple
List<String> matches = map.entrySet()
        .filter(e -> e.getValue().startsWith(e.getKey())
        .collect(Collectors.toList());
String concatenated = String.join("\n", matches);

如果你不想使用流来生成该字符串,代码将如下所示(为了简单起见,此处未使用#entrySet,但在此处使用会更有效率):
List<String> matches = new ArrayList<>();
StringJoiner joiner = new StringJoiner("\n");
for (String key : map.keySet()) {
    String value = map.get(key);
    if (value.startsWith(key)) {
        joiner.add(value);
    }
}
//joiner#toString will give the expected result

谢谢!给答案点个赞。 - Ashok.N

1
利用.merge函数:
Map<String, Object> finalMap = new HashMap<String, Object>();

for (Map map : someObjectsList) {
    for (Object key : map.keySet()) {
        String value = ((String) map.get(key));
        finalMap.merge((String) key, value, (k, v) -> k + "," + v);
    }
}

输出结果如下:

{2017-07-21=2017-07-21-07.33.28.429340,2017-07-21-07.33.28.429540, 2017-07-24=2017-07-24-01.23.33.591340,2017-07-24-01.23.33.492340}


以下一行代码可以实现相同的功能:
someObjectsList.stream()
               .flatMap(i -> i.entrySet().stream())
               .collect(Collectors.toMap(Entry::getKey, Entry::getValue, 
                                        (k, v) -> k + "," + v));

1
你正在寻找处理 List分组 行为。自 起,你可以利用 的优势。无论如何,你都需要一个新的 Map 来存储值以便打印它们。
someObjectsList.stream()
        .flatMap(i -> i.entrySet().stream())               // flatmapping to entries
        .collect(Collectors.groupingBy(Entry::getKey))     // grouping them using the key

如果您想使用for循环。在这种情况下,由于每个列表项中可能会出现更多的条目,因此这将更加困难:

final Map<String, List<Object>> map = new HashMap<>();
for (Map<String, Object> m: someObjectsList) {          // iterate List<Map>
    for (Entry<String, Object> entry: m.entrySet()) {   // iterate entries of each Map
        List<Object> list;
        final String key = entry.getKey();              // key of the entry
        final Object value = entry.getValue();          // value of the entry
        if (map.containsKey(key)) {                     // if the key exists
            list = map.get(key);                        // ... use it
        } else {
            list = new ArrayList<>();                   // ... or else create a new one
        }
        list.add(value);                                // add the new value
        map.put(key, list);                             // and add/update the entry
    }
}

在两种情况下打印出Map<String, List<Object>> map的结果如下:
2017-07-21=[2017-07-21-07.33.28.429340, 2017-07-21-07.33.28.429540], 
2017-07-24=[2017-07-24-01.23.33.591340, 2017-07-24-01.23.33.492340]

谢谢你的帮助。这个解决方案非常有趣。给它加一分。 - Ashok.N

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接