我一直在编写以下内容以尝试更好地理解哈希映射。我有一个由分隔符|
分隔的原始项目列表。目标是确保最后我有一个HashMap,其中每个字母都有一个键,即a
出现在|
之前,并附加到每个字母的列表中包含相关的“日志” ,或者出现在|
之后的那个,即a = [asdf a2,asdf a1]。为了清楚起见,我将a1 / a2放在列表的“日志”部分。假设在真正执行此代码时,那些提示将不存在。我只想根据初始原始分隔列表将所有“日志”分组到相应的键。
程序:
public static void main(String[] args) {
List<String> items = new ArrayList<>();
// Set up raw data
items.add("a|asdf a2");
items.add("b|asdf b1");
items.add("c|asdf c1");
items.add("c|asdf c2");
items.add("c|asdf c3");
items.add("d|asdf d1");
items.add("a|asdf a1");
items.add("e|asdf e1");
items.add("e|asdf e2");
items.add("e|asdf e3");
items.add("e|asdf e4");
// Display raw data
System.out.println("Raw List: " + items);
// Create a hash map
HashMap<String, List<String>> customerHashMap = new HashMap<>();
// Create new lists. One for customers and one for logs
List<String> customerList = new ArrayList<>();
List<String> logList = new ArrayList<>();
for (String item : items) {
String customer = item.split("\\|", 2)[0];
customerList.add(customer);
String log = item.substring(item.indexOf("|") + 1);
logList.add(log);
// Add to hash map
customerHashMap.put(customer, logList);
}
// Display lists
System.out.println("Customer List: " + customerList);
System.out.println("Log List: " + logList);
System.out.println("Hashmap: " + customerHashMap);
// Print out of the final hash map. Customer a should only have "a" logs, customer b with "b", etc.
System.out.println("");
Iterator it = customerHashMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
System.out.println(pair.getKey() + " = " + pair.getValue());
it.remove();
}
}
输出:
a = [asdf a2, asdf b1, asdf c1, asdf c2, asdf c3, asdf d1, asdf a1, asdf e1, asdf e2, asdf e3, asdf e4]
b = [asdf a2, asdf b1, asdf c1, asdf c2, asdf c3, asdf d1, asdf a1, asdf e1, asdf e2, asdf e3, asdf e4]
c = [asdf a2, asdf b1, asdf c1, asdf c2, asdf c3, asdf d1, asdf a1, asdf e1, asdf e2, asdf e3, asdf e4]
d = [asdf a2, asdf b1, asdf c1, asdf c2, asdf c3, asdf d1, asdf a1, asdf e1, asdf e2, asdf e3, asdf e4]
e = [asdf a2, asdf b1, asdf c1, asdf c2, asdf c3, asdf d1, asdf a1, asdf e1, asdf e2, asdf e3, asdf e4]\
期望输出:
a = [asdf a2, asdf a1]
b = [asdf b1]
c = [asdf c1, asdf c2, asdf c3]
d = [asdf d1]
e = [asdf e1, asdf e2, asdf e3, asdf e4]
如何在最后实现所需的输出?
答案 0 :(得分:1)
List<String> logList = new ArrayList<>();
在循环之前声明,并且永远不会重新分配此变量
并且您将其用作与循环中Map
的每个键相关联的值
因此,地图的所有键都引用相同的ArrayList
对象。
您必须为每个不同的密钥创建一个新的ArrayList
并将其与地图中的密钥(put(key,value)
)相关联。
这可以给出:
for (String item : items) {
String customer = item.split("\\|", 2)[0];
customerList.add(customer);
String log = item.substring(item.indexOf("|") + 1);
List<String> logList = customerHashMap.get(customer);
if (logList == null){
logList = new ArrayList<>();
customerHashMap.put(customer, logList);
}
logList.add(log);
}
或者正如JB Nizet建议的那样,使用Map.computeIfAbsent()
(自Java 8开始),既可以显式写入不存在的检查,也可以声明中间局部变量来引用当前的ArrayList
对象。
for (String item : items) {
String customer = item.split("\\|", 2)[0];
customerList.add(customer);
String log = item.substring(item.indexOf("|") + 1);
customerHashMap.computeIfAbsent(customer, c -> new ArrayList<>()).add(log);
}
答案 1 :(得分:1)
您可以根据需要使用Java 8新功能。 使用这一简单的代码,您就可以实现您的要求:
items.stream().collect(Collectors.groupingBy(s -> s.charAt(0), Collectors.mapping(s -> s.substring(2), Collectors.toSet()))).forEach((k,v)-> {
System.out.println(k + " = " + v);
});
forEach函数的结尾是打印结果,但代码结果是带有所需结果的Map:
Map<Character, Set<String>> result = items.stream().collect(Collectors.groupingBy(s -> s.charAt(0), Collectors.mapping(s -> s.substring(2), Collectors.toSet())));
注意:如果元素可以重复,请使用 Collectors.toList()