简体   繁体   中英

List<Item> to Map<Type, List<Item>>, sort keys, sort values, and process

I have a large list of items that I need to convert into a map of items of same type:

List<Item> items = //10^6 items of different types
Map<Type, List<Item>> itemsByType = new ConcurrentHashMap<>();

for (Item item : items) {
    itemsByType.computeIfAbsent(
        item.getType(), 
        i -> new ArrayList<>()
    ).add(item);
}

Each type is then ordered by long type identifier; and, each list of type-items is ordered by long item identifier. And, finally, the ordered list is processed.

This works fine, but I'm wondering if there's a more efficient way to do all of this...?

You can use java-8 groupingBy

Map<Type, List<Item>> itemsByType = items.stream()
    .sorted(Comparator) //for any sorting you can use sorted with comparator 
    .collect(Collectors.groupingBy(Item::getType));

If you want ConcurrentHashMap you can use groupingByConcurrent

ConcurrentMap<Type, List<Item>> itemsByType = items.stream()
    .collect(Collectors.groupingByConcurrent(Item::getType));

You can use the overloaded groupingBy with TreeMap so the map is already sorted based on key

TreeMap<Type, List<Item>> map = list
    .stream()
    .collect(Collectors.groupingBy(
        Item::Type,
        () -> new TreeMap<>(Comparator.comparingLong(Type::getId)), 
        Collectors.toList()));

You can also collect the map with sorted keys and sorted values in one chain

Map<Type, List<Item>> str = list1.stream()
    .collect(
        Collectors.groupingBy(
            Item::Type, 
            () -> new TreeMap<>(Comparator.comparingLong(Type::getId)),
            Collectors.collectingAndThen(
                Collectors.toList(),
                list -> list.stream()
                    .sorted(Comparator.comparingLong(Item::getId))
                    .collect(Collectors.toList()))));

You could use a MultiMap , eg, guava's . Here is their code example:

   ListMultimap<String, String> multimap = ArrayListMultimap.create();
   for (President pres : US_PRESIDENTS_IN_ORDER) {
     multimap.put(pres.firstName(), pres.lastName());
   }
   for (String firstName : multimap.keySet()) {
     List<String> lastNames = multimap.get(firstName);
     out.println(firstName + ": " + lastNames);
   }

... produces output such as:

   Zachary: [Taylor]
   John: [Adams, Adams, Tyler, Kennedy]  // Remember, Quincy!
   George: [Washington, Bush, Bush]
   Grover: [Cleveland, Cleveland]        // Two, non-consecutive terms, rep'ing NJ!
   ...

A TreeMultimap has sorted keys and values, which is what you want, if I understood your title correctly.

A Multimap is particularly useful in case you need to check if a certain value is present for a certain key, because that is supported without getting the collection for the key and then searching that:

multimap.containsEntry("John", "Adams");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM