当前位置:  开发笔记 > 编程语言 > 正文

按值对地图<键,值>进行排序

如何解决《按值对地图<键,值>进行排序》经验,为你挑选了23个好方法。

我是Java的新手,经常发现我需要对Map值进行排序.

由于值不是唯一的,我发现自己将其转换keySet为a array,并通过数组排序对该数组进行排序,并使用自定义比较器对与键关联的值进行排序.

有没有更简单的方法?



1> Carter Page..:

这是一个通用友好版本:

public class MapUtil {
    public static > Map sortByValue(Map map) {
        List> list = new ArrayList<>(map.entrySet());
        list.sort(Entry.comparingByValue());

        Map result = new LinkedHashMap<>();
        for (Entry entry : list) {
            result.put(entry.getKey(), entry.getValue());
        }

        return result;
    }
}


很高兴这有帮助.John,LinkedHashMap对解决方案非常重要,因为它提供了可预测的迭代顺序.
Java 8版本不应该使用`forEachOrdered`而不是`forEach`,因为`forEach`的文档声明:"此操作的行为明确是不确定的."?
@ buzz3791是的.任何排序算法都会出现这种情况.在排序期间更改结构中节点的值会创建不可预测(并且几乎总是坏)的结果.
@Sheagorath我在Android上尝试过它也有效.考虑到您使用的是Java 6版本,它不是特定于平台的问题.您是否在价值对象中正确实施了**Comparable**?

2> 小智..:

重要的提示:

此代码可以以多种方式中断.如果您打算使用提供的代码,请务必阅读注释以了解其含义.例如,不能再通过其密钥检索值.(get总是回来null.)


它似乎比上述所有内容容易得多.使用TreeMap如下:

public class Testing {
    public static void main(String[] args) {
        HashMap map = new HashMap();
        ValueComparator bvc = new ValueComparator(map);
        TreeMap sorted_map = new TreeMap(bvc);

        map.put("A", 99.5);
        map.put("B", 67.4);
        map.put("C", 67.4);
        map.put("D", 67.3);

        System.out.println("unsorted map: " + map);
        sorted_map.putAll(map);
        System.out.println("results: " + sorted_map);
    }
}

class ValueComparator implements Comparator {
    Map base;

    public ValueComparator(Map base) {
        this.base = base;
    }

    // Note: this comparator imposes orderings that are inconsistent with
    // equals.
    public int compare(String a, String b) {
        if (base.get(a) >= base.get(b)) {
            return -1;
        } else {
            return 1;
        } // returning 0 would merge keys
    }
}

输出:

unsorted map: {D=67.3, A=99.5, B=67.4, C=67.4}
results: {D=67.3, B=67.4, C=67.4, A=99.5}


以防人们不清楚:如果你有多个键映射到相同的值,这个解决方案可能不会做你想要的 - 只有其中一个键出现在排序结果中.
路易·沃瑟曼(是的,谷歌番石榴的球员之一),实际上是不喜欢这样的回答颇有几分:"它打破了几个真的混淆的方式,如果你连看很可笑.如果底层映射的变化,它会破坏如果有多个按键.映射到相同的值,这将打破,如果你调用get上的一个键,是不是在底层映射,这将打破,如果你做任何事情,任何会导致查找到的关键不在发生地图 - 一个Map.equals调用,containsKey,任何东西 - 它会破坏真正奇怪的堆栈跟踪." https://plus.google.com/102216152814616302326/posts/bEQLDK712MJ
用于树图的比较器与equals不一致(参见sortMap javadox).这意味着从树形图中退出项目将不起作用.sorted_map.get("A")将返回null.这意味着树图的使用被打破了.
不再是(http://stackoverflow.com/questions/109383/how-to-sort-a-mapkey-value-on-the-values-in-java/3420912#3420912).另外,为什么有演员要Double?它不应该只是`return((Comparable)base.get(a).compareTo(((Comparable)base.get(b)))`?
@Stephen:不会.在这种情况下,所有等于值的键都会被删除(等于和比较之间的差异).另外:即使这段代码也存在以下序列问题:map.put("A","1d"); map.put("B","1d"); map.put("C",67d); map .把( "d",99.5d);`
我很遗憾使用这种方法.现在我在我的代码中再现了评论中描述的所有错误.我的错误不在于阅读评论.这http://stackoverflow.com/a/2581754/1537800工作得很好.
这实际上是一个错误...我可以想象一下很少的用例,省略了两个具有相同价值的地图条目之一......
`var sorted_map = map.OrderByDescending(entry => entry.Value);`(在C#中).对不起,我无法抗拒;)但是+1
如果ValueComparator#compare()没有为equals返回0(参见编辑的答案)@ Maxy-B关于缺失键的评论不再适用

3> Brian Goetz..:

Java 8提供了一个新的答案:将条目转换为流,并使用Map.Entry中的比较器组合器:

Stream> sorted =
    map.entrySet().stream()
       .sorted(Map.Entry.comparingByValue());

这将允许您使用按值的升序排序的条目.如果要降序值,只需反转比较器:

Stream> sorted =
    map.entrySet().stream()
       .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));

如果值不具有可比性,则可以传递显式比较器:

Stream> sorted =
    map.entrySet().stream()
       .sorted(Map.Entry.comparingByValue(comparator));

然后,您可以继续使用其他流操作来使用数据.例如,如果您想要新地图中的前10名:

Map topTen =
    map.entrySet().stream()
       .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
       .limit(10)
       .collect(Collectors.toMap(
          Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));

或打印到System.out:

map.entrySet().stream()
   .sorted(Map.Entry.comparingByValue())
   .forEach(System.out::println);


它将并行工作,但是,您可能会发现合并地图以合并部分结果的成本太高,并行版本可能无法达到您希望的效果.但它确实有效并产生正确的答案.
你不必在top10例子中使用compareByValue吗?

4> Stephen..:

三个1行答案......

我会使用Google Collections Guava来执行此操作 - 如果您的值是Comparable可以使用的话

valueComparator = Ordering.natural().onResultOf(Functions.forMap(map))

这将为地图创建一个函数(对象)[将任何键作为输入,返回相应的值],然后对它们[值]应用自然(可比较)排序.

如果他们没有可比性,那么你需要做一些事情

valueComparator = Ordering.from(comparator).onResultOf(Functions.forMap(map)) 

这些可以应用于TreeMap(作为Orderingextends Comparator),或者在某些排序后应用于LinkedHashMap

注意:如果您打算使用TreeMap,请记住,如果比较== 0,那么该项目已经在列表中(如果您有多个比较相同的值,则会发生这种情况).为了缓解这个问题,您可以将密钥添加到比较器中(假设您的密钥和值是Comparable):

valueComparator = Ordering.natural().onResultOf(Functions.forMap(map)).compound(Ordering.natural())

= 对键映射的值应用自然排序,并使用键的自然顺序对其进行复合

请注意,如果您的密钥与0比较,这仍然不起作用,但这应该足以满足大多数comparable项目(因为hashCode,equals并且compareTo通常是同步的...)

请参阅Ordering.onResultOf()和Functions.forMap().

履行

所以现在我们已经有了一个可以满足我们想要的比较器,我们需要从中获得结果.

map = ImmutableSortedMap.copyOf(myOriginalMap, valueComparator);

现在这很可能会起作用,但是:

    需要完成一个完整的完成地图

    不要尝试上面的比较器TreeMap; 没有必要尝试比较插入的键,直到它没有值,直到放置之后,即,它会非常快地中断

第1点对我来说是一个破坏性的事情; 谷歌收藏是非常懒惰(这是好的:你可以在瞬间完成几乎所有的操作;真正的工作是在你开始使用结果时完成的),这需要复制整个地图!

"完整"答案/按值排序的实时排序地图

不过不用担心; 如果你对以这种方式排序的"实时"地图足够痴迷,你可以解决上述问题中的一个而不是两个(!),如下所示:

注意:这在2012年6月发生了显着变化 - 之前的代码永远不会起作用:需要内部HashMap来查找值而不在TreeMap.get()- > compare()compare()- > 之间创建无限循环get()

import static org.junit.Assert.assertEquals;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import com.google.common.base.Functions;
import com.google.common.collect.Ordering;

class ValueComparableMap,V> extends TreeMap {
    //A map for doing lookups on the keys for comparison so we don't get infinite loops
    private final Map valueMap;

    ValueComparableMap(final Ordering partialValueOrdering) {
        this(partialValueOrdering, new HashMap());
    }

    private ValueComparableMap(Ordering partialValueOrdering,
            HashMap valueMap) {
        super(partialValueOrdering //Apply the value ordering
                .onResultOf(Functions.forMap(valueMap)) //On the result of getting the value for the key from the map
                .compound(Ordering.natural())); //as well as ensuring that the keys don't get clobbered
        this.valueMap = valueMap;
    }

    public V put(K k, V v) {
        if (valueMap.containsKey(k)){
            //remove the key in the sorted set before adding the key again
            remove(k);
        }
        valueMap.put(k,v); //To get "real" unsorted values for the comparator
        return super.put(k, v); //Put it in value order
    }

    public static void main(String[] args){
        TreeMap map = new ValueComparableMap(Ordering.natural());
        map.put("a", 5);
        map.put("b", 1);
        map.put("c", 3);
        assertEquals("b",map.firstKey());
        assertEquals("a",map.lastKey());
        map.put("d",0);
        assertEquals("d",map.firstKey());
        //ensure it's still a map (by overwriting a key, but with a new value) 
        map.put("d", 2);
        assertEquals("b", map.firstKey());
        //Ensure multiple values do not clobber keys
        map.put("e", 2);
        assertEquals(5, map.size());
        assertEquals(2, (int) map.get("e"));
        assertEquals(2, (int) map.get("d"));
    }
 }

当我们放置时,我们确保哈希映射具有比较器的值,然后放入TreeSet进行排序.但在此之前,我们检查哈希映射以查看密钥实际上并不重复.此外,我们创建的比较器还将包含密钥,以便重复值不会删除非重复键(由于==比较).这两项对于确保保留地图合同至关重要 ; 如果你认为你不想那样,那么你几乎就是完全颠倒了地图(to Map).

需要将构造函数调用为

 new ValueComparableMap(Ordering.natural());
 //or
 new ValueComparableMap(Ordering.from(comparator));



5> devinmoore..:

来自http://www.programmersheaven.com/download/49349/download.aspx

private static  Map sortByValue(Map map) {
    List> list = new LinkedList<>(map.entrySet());
    Collections.sort(list, new Comparator() {
        @SuppressWarnings("unchecked")
        public int compare(Object o1, Object o2) {
            return ((Comparable) ((Map.Entry) (o1)).getValue()).compareTo(((Map.Entry) (o2)).getValue());
        }
    });

    Map result = new LinkedHashMap<>();
    for (Iterator> it = list.iterator(); it.hasNext();) {
        Map.Entry entry = (Map.Entry) it.next();
        result.put(entry.getKey(), entry.getValue());
    }

    return result;
}


要排序的列表是"new LinkedList"?? 啧啧.谢天谢地,Collections.sort()首先将列表转储到数组中,以避免产生这种错误(但是,将ArrayList转储到数组应该比对LinkedList执行相同操作更快).
@ gg.kaspersky我不是说"对LinkedList进行排序很糟糕",但是LinkedList本身在这里是一个糟糕的选择,无论排序如何._Much_更好地使用ArrayList,对于额外的点,在map.size()中确定它的大小.另请参阅http://List.google.com/p/memory-measurer/wiki/ElementCostInDataStructures ArrayList中每个元素的平均成本:LinkedList中每个元素的平均成本为5个字节:24个字节.对于精确大小的ArrayList,平均成本为4个字节.也就是说,LinkedList占用ArrayList所需内存量的*SIX*倍.这只是膨胀
使用上述值已按升序排序.如何降序排序?

6> assylias..:

使用Java 8,您可以使用流api以非常简单的方式执行此操作:

Map sortedMap = map.entrySet().stream()
                         .sorted(Entry.comparingByValue())
                         .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));


找到了一个解决方案 - "Collections.reverseOrder(比较(Entry :: getValue))`
按相反顺序按条目值排序的更好方法是:`Entry.comparingByValue(Comparator.reverseOrder())`

7> volley..:

对键进行排序需要比较器查找每个比较的每个值.一个更具可伸缩性的解决方案将直接使用entrySet,因为这样的值将立即可用于每次比较(尽管我没有用数字来支持).

这是这种东西的通用版本:

public static > List getKeysSortedByValue(Map map) {
    final int size = map.size();
    final List> list = new ArrayList>(size);
    list.addAll(map.entrySet());
    final ValueComparator cmp = new ValueComparator();
    Collections.sort(list, cmp);
    final List keys = new ArrayList(size);
    for (int i = 0; i < size; i++) {
        keys.set(i, list.get(i).getKey());
    }
    return keys;
}

private static final class ValueComparator>
                                     implements Comparator> {
    public int compare(Map.Entry o1, Map.Entry o2) {
        return o1.getValue().compareTo(o2.getValue());
    }
}

有一些方法可以减少上述解决方案的内存轮换.例如,创建的第一个ArrayList可以重新用作返回值; 这需要抑制一些泛型警告,但对于可重用的库代码可能是值得的.此外,不必在每次调用时重新分配比较器.

这是一个更有效但尽管不那么有吸引力的版本:

public static > List getKeysSortedByValue2(Map map) {
    final int size = map.size();
    final List reusedList = new ArrayList(size);
    final List> meView = reusedList;
    meView.addAll(map.entrySet());
    Collections.sort(meView, SINGLE);
    final List keyView = reusedList;
    for (int i = 0; i < size; i++) {
        keyView.set(i, meView.get(i).getKey());
    }
    return keyView;
}

private static final Comparator SINGLE = new ValueComparator();

最后,如果您需要不断访问已排序的信息(而不是仅仅偶尔对其进行排序),则可以使用其他多地图.如果您需要更多详细信息,请告诉我们......



8> p3t0r..:

commons-collections库包含一个名为TreeBidiMap的解决方案.或者,您可以查看Google Collections API.它有你可以使用的TreeMultimap.

如果你不想使用这些框架......它们带有源代码.


BidiMap的问题在于它在键和值之间增加了1:1的关系约束,以使关系可逆(即,键和值都必须是唯一的).这意味着您不能使用它来存储类似于字数对象的内容,因为许多单词将具有相同的计数.
是的,但在对mapentries的_value_部分进行排序时,TreeMap的灵活性要小得多.

9> Anthony..:

我已经查看了给定的答案,但是当很多键具有相同的值时,其中很多都比需要的更复杂或者删除了地图元素.

这是一个我觉得更合适的解决方案:

public static > Map sortByValues(final Map map) {
    Comparator valueComparator =  new Comparator() {
        public int compare(K k1, K k2) {
            int compare = map.get(k2).compareTo(map.get(k1));
            if (compare == 0) return 1;
            else return compare;
        }
    };
    Map sortedByValues = new TreeMap(valueComparator);
    sortedByValues.putAll(map);
    return sortedByValues;
}

请注意,地图从最高值到最低值排序.


问题:如果你想稍后使用返回的地图,例如检查它是否包含某个元素,你将总是得到假,因为你的自定义比较器!一个可能的解决方案:用最后一行替换:return new LinkedHashMap (sortedByValues);

10> gdejohn..:

要使用Java 8中的新功能实现此目的:

import static java.util.Map.Entry.comparingByValue;
import static java.util.stream.Collectors.toList;

 List> sort(Map map, Comparator comparator) {
    return map.entrySet().stream().sorted(comparingByValue(comparator)).collect(toList());
}

条目按照给定的比较器的值排序.或者,如果您的值可以相互比较,则不需要显式比较器:

> List> sort(Map map) {
    return map.entrySet().stream().sorted(comparingByValue()).collect(toList());
}

返回的列表是调用此方法时给定映射的快照,因此两者都不会反映对另一个的后续更改.对于地图的实时可迭代视图:

> Iterable> sort(Map map) {
    return () -> map.entrySet().stream().sorted(comparingByValue()).iterator();
}

返回的iterable在每次迭代时都会创建给定映射的新快照,因此除非进行并发修改,否则它将始终反映映射的当前状态.



11> 小智..:

创建自定义比较器并在创建新TreeMap对象时使用它.

class MyComparator implements Comparator {

    Map map;

    public MyComparator(Map map) {
        this.map = map;
    }

    public int compare(Object o1, Object o2) {

        if (map.get(o2) == map.get(o1))
            return 1;
        else
            return ((Integer) map.get(o2)).compareTo((Integer)     
                                                            map.get(o1));

    }
}


在主函数中使用以下代码

    Map lMap = new HashMap();
    lMap.put("A", 35);
    lMap.put("B", 75);
    lMap.put("C", 50);
    lMap.put("D", 50);

    MyComparator comparator = new MyComparator(lMap);

    Map newMap = new TreeMap(comparator);
    newMap.putAll(lMap);
    System.out.println(newMap);

输出:

{B=75, D=50, C=50, A=35}



12> Lyudmil..:

虽然我同意对地图进行排序的不断需要可能是一种气味,但我认为以下代码是最简单的方法,而不使用不同的数据结构.

public class MapUtilities {

public static > List> sortByValue(Map map) {
    List> entries = new ArrayList>(map.entrySet());
    Collections.sort(entries, new ByValue());
    return entries;
}

private static class ByValue> implements Comparator> {
    public int compare(Entry o1, Entry o2) {
        return o1.getValue().compareTo(o2.getValue());
    }
}

}

这是一个令人尴尬的不完整的单元测试:

public class MapUtilitiesTest extends TestCase {
public void testSorting() {
    HashMap map = new HashMap();
    map.put("One", 1);
    map.put("Two", 2);
    map.put("Three", 3);

    List> sorted = MapUtilities.sortByValue(map);
    assertEquals("First", "One", sorted.get(0).getKey());
    assertEquals("Second", "Two", sorted.get(1).getKey());
    assertEquals("Third", "Three", sorted.get(2).getKey());
}

}

结果是Map.Entry对象的排序列表,您可以从中获取键和值.



13> 小智..:

使用通用比较器,例如:

final class MapValueComparator> implements Comparator {

    private Map map;

    private MapValueComparator() {
        super();
    }

    public MapValueComparator(Map map) {
        this();
        this.map = map;
    }

    public int compare(K o1, K o2) {
        return map.get(o1).compareTo(map.get(o2));
    }
}



14> michel.iamit..:

当你有两个相等的项目时,最多投票的答案不起作用.TreeMap保留相同的值.

exmaple:未分类的地图

key/value: D/67.3
key/value: A/99.5
key/value: B/67.4
key/value: C/67.5
key/value: E/99.5

结果

key/value: A/99.5
key/value: C/67.5
key/value: B/67.4
key/value: D/67.3

离开E !!

对我来说,它可以很好地调整比较器,如果它等于不返回0但是-1.

在示例中:

class ValueComparator实现Comparator {

地图基地; public ValueComparator(Map base){this.base = base; }

public int compare(Object a,Object b){

if((Double)base.get(a) < (Double)base.get(b)) {
  return 1;
} else if((Double)base.get(a) == (Double)base.get(b)) {
  return -1;
} else {
  return -1;
}

}}

现在它返回:

未分类的地图:

key/value: D/67.3
key/value: A/99.5
key/value: B/67.4
key/value: C/67.5
key/value: E/99.5

结果:

key/value: A/99.5
key/value: E/99.5
key/value: C/67.5
key/value: B/67.4
key/value: D/67.3

作为对Aliens的回应(2011年11月22日):我使用这个解决方案来获取I​​nteger Id和名称的地图,但是这个想法是一样的,所以上面的代码可能不正确(我会在测试中写出来)并给出正确的代码),这是基于上述解决方案的Map排序代码:

package nl.iamit.util;

import java.util.Comparator;
import java.util.Map;

public class Comparators {


    public static class MapIntegerStringComparator implements Comparator {

        Map base;

        public MapIntegerStringComparator(Map base) {
            this.base = base;
        }

        public int compare(Object a, Object b) {

            int compare = ((String) base.get(a))
                    .compareTo((String) base.get(b));
            if (compare == 0) {
                return -1;
            }
            return compare;
        }
    }


}

这是测试类(我刚测试过,这适用于Integer,String Map:

package test.nl.iamit.util;

import java.util.HashMap;
import java.util.TreeMap;
import nl.iamit.util.Comparators;
import org.junit.Test;
import static org.junit.Assert.assertArrayEquals;

public class TestComparators {


    @Test
    public void testMapIntegerStringComparator(){
        HashMap unSoretedMap = new HashMap();
        Comparators.MapIntegerStringComparator bvc = new Comparators.MapIntegerStringComparator(
                unSoretedMap);
        TreeMap sorted_map = new TreeMap(bvc);
        //the testdata:
        unSoretedMap.put(new Integer(1), "E");
        unSoretedMap.put(new Integer(2), "A");
        unSoretedMap.put(new Integer(3), "E");
        unSoretedMap.put(new Integer(4), "B");
        unSoretedMap.put(new Integer(5), "F");

        sorted_map.putAll(unSoretedMap);

        Object[] targetKeys={new Integer(2),new Integer(4),new Integer(3),new Integer(1),new Integer(5) };
        Object[] currecntKeys=sorted_map.keySet().toArray();

        assertArrayEquals(targetKeys,currecntKeys);
    }
}

这是地图比较器的代码:

public static class MapStringDoubleComparator implements Comparator {

    Map base;

    public MapStringDoubleComparator(Map base) {
        this.base = base;
    }

    //note if you want decending in stead of ascending, turn around 1 and -1
    public int compare(Object a, Object b) {
        if ((Double) base.get(a) == (Double) base.get(b)) {
            return 0;
        } else if((Double) base.get(a) < (Double) base.get(b)) {
            return -1;
        }else{
            return 1;
        }
    }
}

这是对此的测试用例:

@Test
public void testMapStringDoubleComparator(){
    HashMap unSoretedMap = new HashMap();
    Comparators.MapStringDoubleComparator bvc = new Comparators.MapStringDoubleComparator(
            unSoretedMap);
    TreeMap sorted_map = new TreeMap(bvc);
    //the testdata:
    unSoretedMap.put("D",new Double(67.3));
    unSoretedMap.put("A",new Double(99.5));
    unSoretedMap.put("B",new Double(67.4));
    unSoretedMap.put("C",new Double(67.5));
    unSoretedMap.put("E",new Double(99.5));

    sorted_map.putAll(unSoretedMap);

    Object[] targetKeys={"D","B","C","E","A"};
    Object[] currecntKeys=sorted_map.keySet().toArray();

    assertArrayEquals(targetKeys,currecntKeys);
}

cource你可以使它更通用,但我只需要1个案例(地图)



15> ciamej..:

而不是Collections.sort像我建议的那样使用Arrays.sort.实际上Collections.sort是这样的:

public static > void sort(List list) {
    Object[] a = list.toArray();
    Arrays.sort(a);
    ListIterator i = list.listIterator();
    for (int j=0; j

它只是调用toArray列表然后使用Arrays.sort.这样,所有映射条目将被复制三次:一次从映射到临时列表(无论是LinkedList还是ArrayList),然后到临时数组,最后到新映射.

我的解决方案省略了这一步,因为它不会创建不必要的LinkedList.这是代码,通用友好和性能最佳:

public static > Map sortByValue(Map map) 
{
    @SuppressWarnings("unchecked")
    Map.Entry[] array = map.entrySet().toArray(new Map.Entry[map.size()]);

    Arrays.sort(array, new Comparator>() 
    {
        public int compare(Map.Entry e1, Map.Entry e2) 
        {
            return e1.getValue().compareTo(e2.getValue());
        }
    });

    Map result = new LinkedHashMap();
    for (Map.Entry entry : array)
        result.put(entry.getKey(), entry.getValue());

    return result;
}



16> Roger..:

这是Anthony的答案的变体,如果存在重复值,则不起作用:

public static > Map sortMapByValues(final Map map) {
    Comparator valueComparator =  new Comparator() {
        public int compare(K k1, K k2) {
            final V v1 = map.get(k1);
            final V v2 = map.get(k2);

            /* Not sure how to handle nulls ... */
            if (v1 == null) {
                return (v2 == null) ? 0 : 1;
            }

            int compare = v2.compareTo(v1);
            if (compare != 0)
            {
                return compare;
            }
            else
            {
                Integer h1 = k1.hashCode();
                Integer h2 = k2.hashCode();
                return h2.compareTo(h1);
            }
        }
    };
    Map sortedByValues = new TreeMap(valueComparator);
    sortedByValues.putAll(map);
    return sortedByValues;
}

请注意,它是如何处理空值的.

这种方法的一个重要优点是它实际上返回了一个Map,与此处提供的其他一些解决方案不同.



17> Nilesh Jadav..:

最佳方法

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry; 

public class OrderByValue {

  public static void main(String a[]){
    Map map = new HashMap();
    map.put("java", 20);
    map.put("C++", 45);
    map.put("Unix", 67);
    map.put("MAC", 26);
    map.put("Why this kolavari", 93);
    Set> set = map.entrySet();
    List> list = new ArrayList>(set);
    Collections.sort( list, new Comparator>()
    {
        public int compare( Map.Entry o1, Map.Entry o2 )
        {
            return (o1.getValue()).compareTo( o2.getValue() );//Ascending order
            //return (o2.getValue()).compareTo( o1.getValue() );//Descending order
        }
    } );
    for(Map.Entry entry:list){
        System.out.println(entry.getKey()+" ==== "+entry.getValue());
    }
  }}

产量

java ==== 20

MAC ==== 26

C++ ==== 45

Unix ==== 67

Why this kolavari ==== 93



18> 小智..:

主要问题.如果您使用第一个答案(Google将您带到此处),请更改比较器以添加相等的子句,否则您无法通过键从sorted_map获取值:

public int compare(String a, String b) {
        if (base.get(a) > base.get(b)) {
            return 1;
        } else if (base.get(a) < base.get(b)){
            return -1;
        } 

        return 0;
        // returning 0 would merge keys
    }



19> David Bleckm..:

这个问题已经有很多答案了,但没有一个提供我正在寻找的东西,一个地图实现返回按关联值排序的键和条目,并将此属性维护为键,并在地图中修改值.两个其他 问题询问此特别.

我编写了一个通用的友好示例来解决这个用例.此实现不遵守Map接口的所有合同,例如反映从原始对象中的keySet()和entrySet()返回的集合中的值更改和删除.我觉得这样的解决方案太大而无法包含在Stack Overflow答案中.如果我设法创建一个更完整的实现,也许我会将它发布到Github然后链接到这个答案的更新版本.

import java.util.*;

/**
 * A map where {@link #keySet()} and {@link #entrySet()} return sets ordered
 * by associated values based on the the comparator provided at construction
 * time. The order of two or more keys with identical values is not defined.
 * 

* Several contracts of the Map interface are not satisfied by this minimal * implementation. */ public class ValueSortedMap extends HashMap { protected Map> valueToKeysMap; // uses natural order of value object, if any public ValueSortedMap() { this((Comparator) null); } public ValueSortedMap(Comparator valueComparator) { this.valueToKeysMap = new TreeMap>(valueComparator); } public boolean containsValue(Object o) { return valueToKeysMap.containsKey(o); } public V put(K k, V v) { V oldV = null; if (containsKey(k)) { oldV = get(k); valueToKeysMap.get(oldV).remove(k); } super.put(k, v); if (!valueToKeysMap.containsKey(v)) { Collection keys = new ArrayList(); keys.add(k); valueToKeysMap.put(v, keys); } else { valueToKeysMap.get(v).add(k); } return oldV; } public void putAll(Map m) { for (Map.Entry e : m.entrySet()) put(e.getKey(), e.getValue()); } public V remove(Object k) { V oldV = null; if (containsKey(k)) { oldV = get(k); super.remove(k); valueToKeysMap.get(oldV).remove(k); } return oldV; } public void clear() { super.clear(); valueToKeysMap.clear(); } public Set keySet() { LinkedHashSet ret = new LinkedHashSet(size()); for (V v : valueToKeysMap.keySet()) { Collection keys = valueToKeysMap.get(v); ret.addAll(keys); } return ret; } public Set> entrySet() { LinkedHashSet> ret = new LinkedHashSet>(size()); for (Collection keys : valueToKeysMap.values()) { for (final K k : keys) { final V v = get(k); ret.add(new Map.Entry() { public K getKey() { return k; } public V getValue() { return v; } public V setValue(V v) { throw new UnsupportedOperationException(); } }); } } return ret; } }



20> Ryan Delucch..:

根据上下文,使用java.util.LinkedHashMap哪个记住项目放入地图的顺序.否则,如果您需要根据其自然顺序对值进行排序,我建议您维护一个可以进行排序的单独List Collections.sort().



21> 小智..:

这太复杂了.地图不应该按照Value对它们进行排序.最简单的方法是创建自己的类,以满足您的要求.

在示例中,您应该在*所在的位置添加TreeMap比较器.但是通过java API,它只为比较器提供键,而不是值.此处所述的所有示例均基于2个地图.一个哈希和一个新树.这很奇怪.

这个例子:

Map map = new TreeMap(*);

因此,将地图更改为一组:

ResultComparator rc = new ResultComparator();
Set set = new TreeSet(rc);

你将创建类Results,

public class Results {
    private Driver driver;
    private Float time;

    public Results(Driver driver, Float time) {
        this.driver = driver;
        this.time = time;
    }

    public Float getTime() {
        return time;
    }

    public void setTime(Float time) {
        this.time = time;
    }

    public Driver getDriver() {
        return driver;
    }

    public void setDriver (Driver driver) {
        this.driver = driver;
    }
}

和比较者类:

public class ResultsComparator implements Comparator {
    public int compare(Results t, Results t1) {
        if (t.getTime() < t1.getTime()) {
            return 1;
        } else if (t.getTime() == t1.getTime()) {
            return 0;
        } else {
            return -1;
        }
    }
}

这样您就可以轻松添加更多依赖项.

最后一点我将添加简单的迭代器:

Iterator it = set.iterator();
while (it.hasNext()) {
    Results r = (Results)it.next();
    System.out.println( r.getDriver().toString
        //or whatever that is related to Driver class -getName() getSurname()
        + " "
        + r.getTime()
        );
}



22> malix..:

由于TreeMap <>不适用于可以相等的值,我使用了这个:

private > List> sort(Map map)     {
    List> list = new LinkedList>(map.entrySet());
    Collections.sort(list, new Comparator>() {
        public int compare(Map.Entry o1, Map.Entry o2) {
            return o1.getValue().compareTo(o2.getValue());
        }
    });

    return list;
}

您可能希望将列表放在LinkedHashMap中,但如果您只是立即迭代它,这是多余的......



23> Pankaj Singh..:

迟到。

随着Java-8的出现,我们可以以非常简单/简洁的方式将流用于数据处理。您可以使用流按值对映射条目进行排序,并创建一个LinkedHashMap来保留插入顺序的迭代。

例如:

LinkedHashMap sortedByValueMap = map.entrySet().stream()
                .sorted(comparing(Entry::getValue).thenComparing(Entry::getKey))     //first sorting by Value, then sorting by Key(entries with same value)
                .collect(LinkedHashMap::new,(map,entry) -> map.put(entry.getKey(),entry.getValue()),LinkedHashMap::putAll);

对于逆序订购,请更换:

comparing(Entry::getValue).thenComparing(Entry::getKey)

comparing(Entry::getValue).thenComparing(Entry::getKey).reversed()

推荐阅读
雨天是最美
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有