1

Today, I will introduce a practical little knowledge point, how to convert List to Map<Object, List<Object>>

<!-- more -->

1. Basic writing

The first introduction is of course the most common and intuitive way of writing, and of course any restricted way of writing

 // 比如将下面的列表,按照字符串长度进行分组
List<String> list = new ArrayList<>();
list.add("hello");
list.add("word");
list.add("come");
list.add("on");
Map<Integer, List<String>> ans = new HashMap<>();

for(String str: list) {
    List<String> sub = ans.get(str.length());
    if(sub == null) {
        sub = new ArrayList<>();
        ans.put(str.length(), sub);
    }
    sub.add(str);
}
System.out.println(ans);

For jdk8+, the content in the above for loop can be replaced by Map.computeIfAbsent , the specific writing is as follows

 for (String str : list) {
    ans.computeIfAbsent(str.length(), k -> new ArrayList<>()).add(str);
}

Of course, since it is already jdk1.8, with the stream processing of Stream, the above step can be simplified, as follows

 Map<Integer, List<String>> ans = list.stream().collect(Collectors.groupingBy(String::length));

2. General approach

The above is for a specific list, for business development and transformation, then we will try to build a general tool class next

The knowledge point we mainly use here is generics, and an important point is how to get the key in the Map

For the writing method of jdk < 1.8, the acquisition posture of the key is defined through the interface

 public static <K, V> Map<K, List<V>> toMapList(List<V> list, KeyFunc<V, K> keyFunc) {
    Map<K, List<V>> result = new HashMap<>();
    for (V item: list) {
        K key = keyFunc.getKey(item);
        if (!result.containsKey(key)) {
            result.put(key, new ArrayList<>());
        }
        result.get(key).add(item);
    }
    return result;
}

public static interface KeyFunc<T, K> {
    K getKey(T t);
}

Use the demo as follows

 public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("hello");
    list.add("word");
    list.add("come");
    list.add("on");
    Map<Integer, List<String>> res = toMapList(list, new KeyFunc<String, Integer>() {
        @Override
        public Integer getKey(String s) {
            return s.length();
        }
    });
    System.out.println(res);
}

Next, let's take a look at the writing method after jdk1.8, combined with stream + function method to achieve

 public static <K, V> Map<K, List<V>> toMapList(List<V> list, Function<V, K> func) {
    return list.stream().collect(Collectors.groupingBy(func));
}

The corresponding usage is as follows

 public static void main(String[] args) {
    List<String> list = new ArrayList<>();
    list.add("hello");
    list.add("word");
    list.add("come");
    list.add("on");
    Map<Integer, List<String>> res = toMapList(list, (Function<String, Integer>) String::length);
    System.out.println(res);
}
  1. Tools

The previous section introduced the implementation of generic conversion tool classes based on generics + jdk8 Stream + function methods. Next, let's summarize and output a tool class suitable for 1.8 and later.

 /**
 * List<V>转换为Map<K, List<V>> 特点在于Map中的value,是个列表,且列表中的元素就是从原列表中的元素
 *
 * @param list
 * @param func 基于list#item生成Map.key的函数方法
 * @param <K>
 * @param <V>
 * @return
 */
public static <K, V> Map<K, List<V>> toMapList(List<V> list, Function<V, K> func) {
    return list.stream().collect(Collectors.groupingBy(func));
}

/**
 * List<I>转换为Map<K, List<V>> 特点在于Map中的value是个列表,且列表中的元素是由list.item转换而来
 *
 * @param list
 * @param keyFunc 基于list#item生成的Map.key的函数方法
 * @param valFunc 基于list#item转换Map.value列表中元素的函数方法
 * @param <K>
 * @param <I>
 * @param <V>
 * @return
 */
public static <K, I, V> Map<K, List<V>> toMapList(List<I> list, Function<I, K> keyFunc, Function<I, V> valFunc) {
    return list.stream().collect(Collectors.groupingBy(keyFunc, Collectors.mapping(valFunc, Collectors.toList())));
}

4.Guava HashMultimap extended knowledge points

Finally, an extended knowledge point is introduced. The Gauva toolkit provides a tool class HashMultimap . Its usage posture is no different from our usual Map, but it should be noted that its value is a gather

 List<String> list = new ArrayList<>();
list.add("hello");
list.add("word");
list.add("come");
list.add("on");
list.add("on");
HashMultimap<Integer, String> map = HashMultimap.create();
for (String item: strList) {
    map.put(item.length(), item);
}
System.out.println(map);

The actual output is as follows, which verifies that the value is actually a set (there is only one on, if it is our tool class above, it will output two)

 {2=[on], 4=[word, come], 5=[hello]}

A grey contact

It is better to have no books than no books. The above content is purely from one family. Due to limited personal ability, there are inevitably omissions and mistakes. If you find bugs or have better suggestions, you are welcome to criticize and correct them. Thank you

QrCode


小灰灰Blog
251 声望46 粉丝