【问题标题】:how to write java 8 Comparator for Map values inside Map.Entry如何为 Map.Entry 中的 Map 值编写 java 8 Comparator
【发布时间】:2017-03-31 17:38:39
【问题描述】:

这是我所拥有的,我想对条目中的值进行降序排序。

Map<String, Outer> outer = Input
                          .entrySet()
                          .stream
                          .collect(toMap(Map.Entry::getKey, entry->{
                           List<Outer> inner = entry
                                    .getValue()
                                    .stream()
                                    .sorted(Comparator.comparingDouble(???))
                              })) ... (more lines of code.)

如何编写带排序的比较器。 如果想在 sorted 里面做如下操作

if (o1.getSomething() > o2.getSomething())
     return -1;
if (o1.getSomething() < o2.getSomething())
     return 1;
return 0;

获得列表并对其进行排序后,它对我有用。

inner.sort((Outer o1, Outer o2) -> {
if (o1.getSomething() > o2.getSomething())
         return -1;
    if (o1.getSomething() < o2.getSomething())
         return 1;
    return 0;
});

但是有没有办法在 entry 中使用 stream.sorted("在这里使用相同的比较器逻辑")。

Entry 是一个 ArrayList,有一堆值。

entry:[{w:1},{w:2},{w:3},{w:4}];

所以我想对此进行反向排序,如下所示:

entry:[{w:4},{w:3},{w:2},{w:1}];

所以我得到的最终列表是按相反顺序排序的。

抱歉造成混乱。

【问题讨论】:

  • 谁投了反对票,也请给出一些解释。
  • getValue() 返回什么类型? (顺便说一句,否决票可能是因为您的问题缺少很多必需的细节,例如我刚刚要求的)
  • @Bohemian 现在很酷。
  • 真的很难看出你想要达到什么。你想按值对地图的条目进行排序(即你想要一个有序的地图)吗?或者您想对映射到地图中某个键的每个列表的元素进行排序?请澄清并向我们展示详细信息。
  • @FedericoPeraltaSchaffner 对映射到映射中键的每个列表的元素进行排序。

标签: java java-8


【解决方案1】:

您可以定义Comparator,然后将stream.sorted() 与内联cmets 一起使用,如下所示:

//Define comparator Lamda exp for Outer class
Comparator<Outer> outerComparator = (o1, o2) -> {
         if (o1.getValue() > o2.getValue())
                return -1;
          else if (o1.getValue() < o2.getValue())
                return 1;
            else 
              return 0;
   };


Map<String, Outer> output = Input.entrySet(). //get elements
        stream(). //get elements
        sorted( //sort elements by passsing outerComparator
        Map.Entry.<String, Outer>comparingByValue(outerComparator)
        .reversed())//reverse for descending order
        .collect(Collectors.toMap(Map.Entry::getKey, 
        Map.Entry::getValue));//collect to Map object

【讨论】:

  • 实际上我正在尝试在条目的 .collect 函数中进行排序。 .collect(toMap(Map.entry::getKey, entry -> {要在这里排序。}))
  • 需要先对元素进行排序,再收集
  • 如何在collect里面写一个排序函数,
【解决方案2】:

如果您只是想获取Map 的值并将它们放入已排序的List,您可以执行以下操作:

Map<String, Element> elMap = new HashMap<>();
elMap.put("3", new Element("3"));
elMap.put("2", new Element("2"));
elMap.put("1", new Element("1"));

List<Element> elList = elMap.values()
        .stream()
        .sorted((e1, e2) -> {
            return e1.getSortField().compareTo(e2.getSortField());
        })
        .collect(Collectors.toList());
System.out.println(elList);

在这里,Element 是一个简单的 POJO,其中包含一个名为 sortFieldString 字段。 sorted() 采用 Comparator。这是一个带有 2 个参数和一个 int 返回类型的功能接口。对于给定的 lambda,这没问题。

你也可以让你的元素实现Comparable。然后你可以这样做:

List<Element> elList = elMap.values()
        .stream()
        .sorted()
        .collect(Collectors.toList());

元素实现正确的接口

static class Element implements Comparable<Element> {
    //Constructor, field, getters
    @Override
    public int compareTo(Element o) {
        return this.sortField.compareTo(o.sortField);
    }
}

编辑:

它是地图中的一个列表,我正在尝试对其进行排序。并尝试在链中对其进行排序。

这可以解释为:

Map<String, List<Element>> collected = elMap.entrySet()
        .stream()
        .peek(entry -> System.out.println("Performing arbitrary Map operations"))
        .collect(Collectors.toMap(Map.Entry::getKey, entry -> {
            return entry.getValue()
                    .stream()
                    .sorted(Comparator.comparingDouble(Element::getWeight))
                    .collect(Collectors.toList());
        }));

collected.entrySet()
        .forEach(entry -> {
            System.out.println(entry.getKey() + " : " + entry.getValue());
        });

您通过 'Map.entrySet()' 流式传输并使用它做任何您想做的事情。根据您的问题将其收集回不同的Map 时,您可以使用上面的示例再次流式传输和收集您的List

【讨论】:

  • 我之前尝试过类似的方法,但是当我尝试评估 e1 时,它无法找到局部变量。 .sorted((e1, e2)-> { if (e1.getWeight() > e2.getWeight()) return -1; if (e1.getWeight()
  • 我不能使用 compareTo 因为返回类型是 double。
  • @patz 你的Comparator 对我来说很好用。另请注意Double.compare(e1.getWeight(), e2.getWeight())。请注意,我正在流式传输这些值。不超过条目。否则,您必须先获取条目的值。
  • 不起作用 .sort((e1, e2) -> Comparator.comparingDouble(e1.getWeight(), e2.getWeight()))
  • 当我这样做时 .sort((e1, e2) -> Double.compare(e1.getWeight(), e2.getWeight())) 我得到未定义的结果
【解决方案3】:

据我所知,您的问题实际上只是如何创建一个排序列表作为地图中的值,并根据 getSomething 的返回进行排序。

entry.getValue().stream()
    .sorted(Comparator.comparing(Outer::getSomething))
    .collect(toList())

将返回根据getSomething 排序的列表。如果该方法返回一个双精度值,那么您可以使用 comparingDouble(Outer::getSomething) 来避免对值进行装箱。

【讨论】:

    【解决方案4】:

    如果我猜对了,您想根据给定的比较器对所有值(列表)进行排序。

    如果是这种情况,您根本不需要创建流。使用MapreplaceAll 方法就足够了:

    // Orders Outer elements according to Outer's getSomething method 
    // in descendant order (assumes getSomething returns a double value)
    Comparator<Outer> yourComparator = 
        Comparator.comparingDouble(Outer::getSomething).reversed();
    
    yourMap.replaceAll((k, v) -> {
            Collections.sort(v, yourComparator);
            return v;
        });
    

    这利用了Collections.sort 方法,它接受一个列表和一个比较器。

    【讨论】:

    • 好吧,如果我必须这样做,我可以在列表中进行排序。因为列表本身有一个排序方法。我正在尝试在创建列表之前进行排序。列表中的条目本身应该被排序。
    • 地图有 K,V,我的列表包含这个值 V。但没有按我想要的顺序排序。一种方法是在将它们插入列表之后或在插入之前对其进行排序。我正在尝试做后者。
    • @patz 那么请澄清列表的元素来自哪里,即它们是否在地图中?我的意思是 Outer 元素的来源。
    • @patz 您如何对这些值进行分组?从我在您的问题中可以看出,每个键似乎只映射到一个元素,那么该单个元素如何成为一个列表?
    • 简化:entry.getValue() 给了我这个条目:[{w:1},{w:2},{w:3},{w:4}];我想要达到的目标。 entry.getValue().stream().sorted("code here") 给我 entry:[{w:4},{w:3},{w:2},{w:1}];跨度>
    【解决方案5】:

    所以这是对我有用的答案。

    .sorted(reverseOrder(comparingDouble(Input::getSomething)))
    

    谢谢大家,

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-11-02
      • 1970-01-01
      • 1970-01-01
      • 2019-08-27
      • 1970-01-01
      • 1970-01-01
      • 2021-09-16
      相关资源
      最近更新 更多