簡體   English   中英

如何對 Map 的條目進行排序<type,list<string> &gt; 按值存儲到 LinkedHashMap </type,list<string>

[英]How do sort Entries of the Map<Type,List<String>> by Value and store into a LinkedHashMap

我有以下Item class:

@AllArgsConstructor
@Getter
public static class Item {
    public enum Type { Meat, Fish }

    private String name;
    private int price;
    private Type type;
}

並且有一個項目List ,如下所示:

List<Item> menu = Arrays.asList(
    new Item("pork" 800, Item.Type.Meat), 
    new Item("beef" 700, Item.Type.Meat), 
    new Item("chicken", 200, Item.Type.meat), 
    new Item("prawns" 300, Item.Type.Fish),
    new Item("salmon", 450, Item.Type.Fish)
);

我需要按TypeItem進行分組並存儲到 map 中。

然后我需要按升序對map 條目Value (在本例中是StringList )進行排序並存儲到LinkedHashMap

如何根據List<String>值對map 條目進行排序?

我的代碼:

// grouping items by type

Map<Item.Type, List<String>> map = menu.stream()
    .collect(Collectors.groupingBy(
        Item:: getType,
        Collectors.mapping(Item::getName, Collectors.toList())
    ));

// a LinkedHashMap to store sorted entries

Map<Item.Type, List<String>> hmap = new LinkedHashMap<>();

// attempting to sort map entries by value and put them
//  into the resulting map

map.entrySet().stream()
    .sorted(Map.Entry.<Item.Type, List<String>> comparingByValue())
    .forEachOrdered(e -> hmap.put(e.getKey(), e.getValue()));

但我得到一個編譯錯誤:

Type parameter 'java.util.List' is not within its bound;
should extend 'java.lang.Comparable<? super java.util.List>'

我認為原因是因為我想要排序的 map 中有一個字符串列表。

當我只有一個String作為時(不是List<String> )。 該代碼運行良好。

Collections 都沒有實現Comparable接口。 這沒有任何意義,因為它們是數據的容器,如果您需要對數據進行排序,您將在能夠維護順序的集合中對其進行排序。 當您需要對 collections 進行排序時 - 這是一項奇怪的任務。

我說的很奇怪,因為像List這樣的 collections 不知道如何比較它們的元素,這意味着元素的可比性不是強制性的,並且在實例化列表時不能提供比較器。 因此,不可能為List建立自然順序,換句話說,列表不“知道”如何與另一個列表進行比較。

您需要為此目的定義一個自定義Comparator器。

當我只有一個String作為值時(不是List<String> )。 該代碼運行良好。

假設您希望比較您的字符串列表,就好像它們中的每一個都是單個字符串一樣(我們稱之為比較鍵),那么提前生成這樣的字符串並將每個Type的項目與比較相關聯是明智的關鍵(如果您有不同的比較策略 - 然后相應地調整代碼)。

比較鍵可以在現場(在流中)生成,但它會導致多次重新創建相同的字符串。 在這種情況下,這不是一個大問題,因為Item.Type是一個枚舉,因此對應於每個枚舉常量的字符串比較鍵的數量是有限的,但提前准備好它們並沒有什么壞處。

List<Item> menu = Arrays.asList(
    new Item("pork", 800, Item.Type.Meat),
    new Item("beef", 700, Item.Type.Meat),
    new Item("chicken", 200, Item.Type.Meat),
    new Item("prawns", 300, Item.Type.Fish),
    new Item("salmon", 450, Item.Type.Fish)
);
    
Map<Item.Type, List<String>> itemNamesByType = menu.stream()
    .collect(Collectors.groupingBy(
        Item:: getType,
        Collectors.mapping(Item::getName, Collectors.toList())
    ));

// generating Comparison Keys for every Type

Map<Item.Type, String> comparisonKeyByType = itemNamesByType.entrySet().stream()
    .collect(Collectors.toMap(
        Map.Entry::getKey,
        entry -> String.join("", entry.getValue())
    ));
    
Map<Item.Type, List<String>> itemNamesByTypeSorted = itemNamesByType.entrySet().stream()
    .sorted(Map.Entry.comparingByKey(
        Comparator.comparing(comparisonKeyByType::get)
    ))
    .collect(Collectors.toMap(
        Map.Entry::getKey,   // keyMapper
        Map.Entry::getValue, // valueMapper
        (left, right) -> { throw new AssertionError("duplicates not expected"); }, // since the source is an entry set - there shouldn't be duplicate keys (but we need to provide this argument in order to be able to use version of toMap() which allows to provide a mapFactory
        LinkedHashMap::new   // mapFactory
    ));
    
itemNamesByTypeSorted.forEach((k, v) -> System.out.println(k + " -> " + v));

Output:

Meat -> [pork, beef, chicken]
Fish -> [prawns, salmon]

只需實現可用的列表方法

  • 比較字符串
public static void main(String[] args) {
        Map<String, List<String>> hmap = new LinkedHashMap<>();
        List<String> values = new ArrayList<>();
        values.add("d");
        values.add("a");
        values.add("g");

        hmap.put("1", values);
        hmap.put("2", values); 

        System.out.println(hmap); // --> {1=[d, a, g], 2=[d, a, g]}

        for(Map.Entry<String,List<String>> entry: hmap.entrySet()){
            entry.getValue().sort(Comparator.naturalOrder());
        }
        System.out.println(hmap); // --> {1=[a, d, g], 2=[a, d, g]}
    }
  • 按屬性列表比較 object
public static void main(String[] args) {
        final List menu = Arrays.asList(
                new Dish("pork", 800, "Meat"),
                new Dish("beef", 700, "Meat"),
                new Dish("chicken", 200, "Meat"),
                new Dish("prawns", 300, "Fish"),
                new Dish("salmon", 450, "Fish"));

        Map<String, List<Dish>> hmap = new LinkedHashMap<>();

        hmap.put("1", menu);
        hmap.put("2", menu);

        System.out.println(hmap); // --> {1=[Dish{name='pork', price=800, type='Meat'}, Dish{name='beef', price=700, type='Meat'}, Dish{name='chicken', price=200, type='Meat'}, Dish{name='prawns', price=300, type='Fish'}, Dish{name='salmon', price=450, type='Fish'}], 2=[Dish{name='pork', price=800, type='Meat'}, Dish{name='beef', price=700, type='Meat'}, Dish{name='chicken', price=200, type='Meat'}, Dish{name='prawns', price=300, type='Fish'}, Dish{name='salmon', price=450, type='Fish'}]}

        for (Map.Entry<String, List<Dish>> entry : hmap.entrySet()) {
            entry.getValue().sort(Comparator.comparing(Dish::getName));
        }
        System.out.println(hmap); // --> {1=[Dish{name='beef', price=700, type='Meat'}, Dish{name='chicken', price=200, type='Meat'}, Dish{name='pork', price=800, type='Meat'}, Dish{name='prawns', price=300, type='Fish'}, Dish{name='salmon', price=450, type='Fish'}], 2=[Dish{name='beef', price=700, type='Meat'}, Dish{name='chicken', price=200, type='Meat'}, Dish{name='pork', price=800, type='Meat'}, Dish{name='prawns', price=300, type='Fish'}, Dish{name='salmon', price=450, type='Fish'}]}

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM