【问题标题】:How to Sort Map<String, List<Summary>>如何排序 Map<String, List<Summary>>
【发布时间】:2018-08-02 19:58:36
【问题描述】:

我需要按列表值元素的属性对地图进行排序。查看代码。

public Map<String, List<Summary>> getMostMentions() throws Exception {

    List<Tweet> tweets;
    try {
        tweets = getApiFromTweet().getTweets();
    } catch (Exception e) {
        throw new Exception(e);
    }


    List<Summary> summary = new ArrayList<>();

    tweets.forEach(t -> {
        summary.add(
                new Summary(
                        t.getUser().getScreen_name(), 
                        t.getFollowersCount(), 
                        t.getRetweet_count(),                   
                        t.getFavorite_count(), 
                        t.getText(), 
                        t.getCreated_at(),
                        appConfig.getProfileLink(t.getUser().getScreen_name()),
                        appConfig.getTweetLink(t.getUser().getScreen_name(), t.getId())));
    });

    Map<String, List<Summary>> mostMentionsMap = summary.stream().collect(Collectors.groupingBy(Summary::getScreen_name));

    mostMentionsMap.forEach((k,v) -> {
        v.sort(Comparator.comparing(Summary::getFavorite_count).reversed());
    });


    return mostMentionsMap;
}

我需要通过 getFavorite_count 对地图 mostMentionsMap 进行排序 元素列表返回地图排序。 我已经对每个地图项的元素进行了排序,但我需要对地图使用相同的排序标准。

我可以按键排序查看代码。

LinkedHashMap<String, List<SummaryTweet>> mapSorted = mostMentionsMap.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())             
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue, LinkedHashMap::new));

但是,我必须按值(List)的元素的属性进行排序。 不知道我解释的好不好?

【问题讨论】:

  • 您不能对Map 中的键进行排序,您可以对SortedMap 中的键进行排序。当您说“对地图进行排序”时,您到底想对什么进行排序。
  • 你要排序的Summary的属性是什么?既然你有一个ListSummary,你想使用哪个Summary
  • @Slaw 使用 Summary 类的方法 getFavorite_count() 相同的标准。

标签: java lambda java-8 comparator


【解决方案1】:

好吧,从您的问题中可以清楚地看出,您希望按值对 Map 进行排序。你可以这样做:

Comparator<List<Summary>> valueComparator;

LinkedHashMap<String, List<Summary>> mapSorted = mostMentionsMap.entrySet().stream()
        .sorted(Map.Entry.comparingByValue(valueComparator))
        .collect(Collectors.toMap(
                Map.Entry::getKey, Map.Entry::getValue,
                (oldValue, newValue) -> oldValue, // or throw here (just in case)
                LinkedHashMap::new
        ));

现在,不清楚(这就是 Slaw's comment 的意义所在)如何对值进行排序(即 valueComparator 应该是什么)。我们知道您想使用 Summary::getFavorite_count 进行排序,但由于您有一个 ListSummary'ies,因此选项有多个。以下是其中一些选项:

1) 按最大值排序:

// assumes Summaries are sorted by: Comparator.comparing(Summary::getFavorite_count).reversed()
Comparator.<List<Summary>>comparingInt(list -> list.isEmpty()
        ? 0
        : list.get(0).getFavorite_count()
).reversed();

2) 按总数排序:

Comparator.<List<Summary>>comparingInt(list -> list.stream()
        .mapToInt(Summary::getFavorite_count)
        .sum()
).reversed();

3) 按平均排序:

Comparator.<List<Summary>>comparingDouble(list -> list.stream()
        .mapToInt(Summary::getFavorite_count)
        .average().orElse(0)
).reversed();

【讨论】:

  • 感谢您的解决方案非常好。我用以下代码解决了这个问题:LinkedHashMap&lt;String,List&lt;SummaryTweet&gt;&gt; collect = mostMentionsMap.entrySet().stream() .sorted((e1, e2) -&gt; Long.compare(e2.getValue().get(0).getFollowers_count(), e1.getValue().get(0).getFollowers_count())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -&gt; a, LinkedHashMap::new));
  • 请注意,函数式方法(即Comparator.comparing*)虽然可能更长一些,但比直接比较器实现更具可读性。这是您的解决方案的等效功能:Map.Entry.comparingByValue(Comparator.comparing(list -&gt; list.get(0), Comparator.comparingLong(Summary::getFollowers_count).reversed()))
  • 确实代码可读性更强。谢谢@Tomaz! LinkedHashMap&lt;String,List&lt;Summary&gt;&gt; collect = mostMentionsMap.entrySet().stream() .sorted(Map.Entry.comparingByValue(Comparator.comparing(list -&gt; list.get(0), Comparator.comparingLong(Summary::getFollowers_count).reversed()))) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -&gt; a, LinkedHashMap::new));
  • @CristianoFirminoRodrigues 不客气!这是 Tomasz ;)
【解决方案2】:

一般来说,当想要在 Java 中对地图进行特定排序时,您可能应该使用 TreeMap。现在,我假设 .getFavorite_count 返回一个 int ,所以键需要是 Integer 类型,因为我不确定让 String 类型的键对返回类型中的一些 String 类型进行排序。

【讨论】:

    【解决方案3】:

    您可以使用 Comparable 接口:

    public class YourNameOfTheClass implements Comparable</*Your objects, which should be sorted. Example: Car*/> {
    
    /*Your code and stuff…*/
    
        @Override
        public int compareTo(/*Your object, which you wrote above and the name of it. Example: Car myCar*/) {
    
            /*
            Now here you should enter your criteria.
    
            If you want to sort something it should be comparable.
    
            Usually, this method returns '0', when the two objects, which are compared are equal. So you should write something like this:
    
            if (this.getFavourite() == car.getFavourite())
                return 0;
    
            This method returns a negative integer when the first object has a 'smaller' value and a positive integer when it's of greater value.
    
            Example:
            myCar.compareTo(yourCar) would return 0, if we're actually driving the same car. -1 when my Car is not as good as yours and +1 when my Car is better.
            */
        }
    }
    

    定义比较标准后,您可以像这样简单地对其进行排序:

    Collections.sort(/*The name of your list*/)
    

    我来演示一下:

    public class CompareCars implements Comparable<Car> {
    
        public static void main (String [] args) {
            List<Car> allCars = new ArrayList<Car>();
            Collections.sort(allCars);
        }
    
        @Override
        public int compareTo (Car secondCar) {
            if (this.getLicensePlate() == secondCar.getLicensePlate() || this.getHP() == secondCar.getHP())
                return 0;
            if (this.getHP() > secondCar.getHP())
                return 1;
            else
                return -1;
        }
    
    }
    

    您可以阅读更多关于它的信息here。它也应该适用于地图。

    【讨论】:

    • 是的,对列表进行排序非常简单,甚至当值是整数或字符串时的映射,整个问题是当您需要对值是我的情况是对象列表。
    • 如果你想对它们进行排序,你应该能够区分它们。如果您能够区分它们,那么您就可以毫无问题地说出一个列表何时等于另一个。这将是你的回报 0。现在你需要找到你的标准来判断一个列表是更大还是更小。我不知道你的标准。如果您能说明您想使用哪些标准,我可以进一步帮助您。
    猜你喜欢
    • 2016-11-25
    • 1970-01-01
    • 1970-01-01
    • 2015-02-14
    • 1970-01-01
    • 1970-01-01
    • 2020-07-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多