java - ImmutableSortedMap - 映射中的重复键

标签 java sorting guava comparator

我有一个 ImmutableSortedMap,它在以下数据结构中保存数据。

<String, Pair<Long, Double>>

我的目标是从最大的 Double 开始按降序排列这张 map 。如果两个Doubles相同,按 Long 排序。如果都是DoubleLong相同,按String排序

我当前的比较器仅处理第一种情况,如下所示。

private ImmutableSortedMap<String, Pair<Long, Double>> sortInDescendingSizeOrder(final Map<String, Pair<Long, Double>> statsByType) {
    Ordering<String> ordering = Ordering
            .from(new Comparator<Pair<Long, Double>>() {
                @Override
                public int compare(Pair<Long, Double> o, Pair<Long, Double> o2) {
                    return o.getRight().equals(o2.getRight()) ? o.getLeft().compareTo(o2.getLeft()) : o.getRight().compareTo(o2.getRight());
                }
            })
            .reverse()
            .onResultOf(Functions.forMap(statsByType, null));

    return ImmutableSortedMap.copyOf(statsByType, ordering);
}

但是,它找到了两个 Doubles相同并引发以下异常: Exception in thread "main" java.lang.IllegalArgumentException: Duplicate keys in mappings

我不明白我做错了什么......

编辑:我尝试添加 compound方法并按字符串排序(至少)。

.compound(new Comparator<String>() {
                    @Override
                    public int compare(String o1, String o2) {
                        return o1.compareTo(o2);
                    }
                });

这使得代码不会抛出任何异常,但是,结果映射中没有任何顺序。

编辑 2:此时,任何类似于上述

的排序
Map<String, Pair<Long, Double>> 

就可以了。不一定需要是 ImmutableSortedMap

最佳答案

编辑:See Louis' answer对于实际正确的解决方案( ImmutableMap.Builder#orderEntriesByValue(Comparator) )。继续阅读此答案以修复不正确的方法;)

<小时/>

这是 ImmutableSortedMap#copyOf(Map, Comparator) 的记录行为:

Throws:

NullPointerException - if any key or value in map is null
IllegalArgumentException - if any two keys are equal according to the comparator

你得到的是根据比较器得出的值相等的结果,所以问题就在那里。 See this answer for comparing map by value - 正如 Louis 提到的(他来自 Guava 团队),使用 Functions.forMap 很棘手。

在您的情况下,将 .nullsLast() 添加到第一个排序并附加 .compound(Ordering.natural()) 应该可以。例如:

Map<String, Pair<Long, Double>> map = ImmutableMap.of(
        "a", Pair.of(1L, 1.0d),
        "b", Pair.of(1L, 1.0d),
        "c", Pair.of(1L, 1.0d),
        "d", Pair.of(1L, 1.0d)
);

@Test
public void should2()
{
    final ImmutableSortedMap<String, Pair<Long, Double>> sortedMap = sortInDescendingSizeOrder(map);
    assertThat(sortedMap).hasSize(4);
    System.out.println(sortedMap); // {a=(1,1.0), b=(1,1.0), c=(1,1.0), d=(1,1.0)}
}

Map<String, Pair<Long, Double>> map = ImmutableMap.of(
        "a", Pair.of(1L, 1.0d),
        "b", Pair.of(2L, 1.0d),
        "c", Pair.of(1L, 2.0d),
        "d", Pair.of(2L, 2.0d)
);

它输出{d=(2,2.0), b=(2,1.0), c=(1,2.0), a=(1,1.0)}

(sortInDescendingSizeOrder供引用)

private ImmutableSortedMap<String, Pair<Long, Double>> sortInDescendingSizeOrder(
        final Map<String, Pair<Long, Double>> statsByType) {
    Ordering<String> ordering = Ordering.from(new Comparator<Pair<Long, Double>>() {
                @Override
                public int compare(Pair<Long, Double> o, Pair<Long, Double> o2) {
                    return ComparisonChain.start()
                            .compare(o.getRight(), o2.getRight())
                            .compare(o.getLeft(), o2.getLeft())
                            .result();
                }
            })
            .reverse()
            .nullsLast()
            .onResultOf(Functions.forMap(statsByType, null))
            .compound(Ordering.natural());

    return ImmutableSortedMap.copyOf(statsByType, ordering);
}

ComparisonChain是 Guava 的另一个好东西,您可以在这里使用。

关于java - ImmutableSortedMap - 映射中的重复键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40739299/

相关文章:

java - 我想在 Android Activity 中制作一个可滚动的带有图像的文本列表。我应该用什么?

java - 从递归解构建最大子数组动态规划解

java - 用xml编写的文件描述符

java - Guava 事件总线 : Subscribe without annotations?

java - Guava Splitter.onPattern(..).split() 与 String.split(..) 有何不同?

java - 一种更优雅的遍历列表以比较两个相邻元素的方法

c - 合并排序无法正常工作?

mysql - 通过 "Last Week"、 "Last Month"和 "Last Year"搜索记录的选择查询可能是什么?

javascript - 如何为 javascript 排序函数制作一个有效的比较器来对字符串数组进行排序?

java - 从最频繁的 X 条目的多重集中获取有序子集