【问题标题】:Collections.sort for multiple conditions [duplicate]Collections.sort 多个条件[重复]
【发布时间】:2019-08-05 09:44:28
【问题描述】:

我有一个要排序的对象列表。但我有三个不同的条件。这就是为什么我有这个代码:

Collections.sort(myList, new Comparator<MyObject>() {
    @Override
    public int compare(MyObject o1, MyObject o2) {
        // my code
    }
});

三次。首先将条件为x 的所有元素排序到列表底部。然后第二次将条件为y 的所有元素排序到底部,然后再次为条件z 排序。

现在我想知道如何在一个比较方法中组合多个条件。所以我不必这样做三遍。

编辑:更清楚地了解条件。我想将所有具有x 条件的对象排序到列表的底部。如果一个元素满足y 的条件,它应该甚至低于x,同样适用于z

【问题讨论】:

  • 不清楚你所说的“条件”是什么意思是“排序标准”吗?所以按x排序,然后按y,然后按z
  • 你可以有一个compareHelper,它接受第三个参数,指示要排序的属性,然后遵从它。不过,我们可能需要查看相关代码才能提出任何建议。至少,您可以使用 lambda 使其更简洁。
  • 查看番石榴订购baeldung.com/guava-ordering
  • @SharonBenAsher 我编辑了我的代码。也许这可以清除它。

标签: java sorting comparator


【解决方案1】:

您可以使用 Java 流。使用Collection.sort()时也会用到这个:

myList.sort(Comparator.comparing(MyObject::getAttributeX)
    .thenComparing(i -> i.getSomething().getSubValue())
    .thenComparing((a, b) -> a.getInt() - b.getInt()));

如果您使用的是低于 Java 8 的版本,您必须自己在 Comparator 中实现排序逻辑或使用外部库:

Collections.sort(myList, new Comparator<MyObject>() {
    @Override
    public int compare(MyObject a, MyObject b) {
        int cmp0 = a.getAttributeX().compareTo(b.getAttributeX());
        if (cmp0 != 0) {
            return cmp0;
        }
        int cmp1 = a.getSomething().getSubValue().compareTo(b.getSomething().getSubValue());
        if (cmp1 != 0) {
            return cmp1;
        }
        return a.getInt() - b.getInt();
    }
});

【讨论】:

  • 不幸的是,我想要应用此代码的 Android 应用程序中的 API 级别太低,无法使用此功能。
  • 用法:此答案的代码中没有流。有 lambdas。这是不一样的。连接是 lambdas 也经常(但不总是)与流一起使用。
  • @OleV.V.另一个联系是在 Java 8 中引入了 lambdas 和流,这是 OP 在流解决方案中遇到的问题。
  • @OleV.V.另一个更正是,他对 lambda 解决方案没有问题,但对 Comparator.comparing 解决方案(Java 8 中也引入了该解决方案)有意见。此外,“Lambda”也不够用,因为我们正在评论的答案将 Comparator.comparing 参数化为方法引用,而不是 lambda。
  • 不要使用减号来实现比较器。 a.getInt() - b.getInt() 可以溢出。使用Integer.compare(a.getInt(), b.getInt())。在比较器链接的情况下,您可以使用更简单的thenComparingInt(MyObject::getInt) 而不是thenComparing((a, b) -&gt; a.getInt() - b.getInt())
【解决方案2】:

我假设MyObject 有类似的方法

public boolean isX() {
    return // either false or true;
}

那么用这种方式排序是最简单的:

    Collections.sort(myList,
            Comparator.comparing(MyObject::isX)
                    .thenComparing(MyObject::isY)
                    .thenComparing(MyObject::isZ));

由于isX 等返回boolean 值,这些值已排序,false 排在true 之前。因此排序将确保满足 x 条件(isX 返回 true)的所有对象都将出现在列表的末尾。在剩余的对象中,满足 y 的对象将最后移动,就在 x-s 之前。 z 也是如此。

如果 x、y 和 z 是由进行排序的类中的方法确定的呢?在此示例中,我们将其称为 Sorter 类。此类方法可能如下所示:

public static boolean isY(MyObject obj) {
    return // either false or true;
}

您只需将MyObject::isX 替换为Sorter::isX

    Collections.sort(myList,
            Comparator.comparing(Sorter::isX)
                    .thenComparing(Sorter::isY)
                    .thenComparing(Sorter::isZ));

您也可以混合,在Sorter 中定义一些方法,在MyMethod 中定义一些方法。

真正发生的是,返回的 boolean 值被装箱到 Boolean 对象中,然后进行比较,但您不必关心这个细节。

编辑: 较低 Android API 级别的版本:

    Comparator<MyObject> xyzComparator = new Comparator<MyObject>() {

        @Override
        public int compare(MyObject o1, MyObject o2) {
            int diff = Boolean.compare(o1.isX(), o2.isX());
            if (diff != 0) {
                return diff;
            }
            diff = Boolean.compare(o1.isY(), o2.isY());
            if (diff != 0) {
                return diff;
            }
            diff = Boolean.compare(o1.isZ(), o2.isZ());
            // return whether 0 or not
            return diff;
        }
    };
    Collections.sort(myList, xyzComparator);

它甚至保存了上面提到的自动装箱。

【讨论】:

    【解决方案3】:

    例如,您可以使用比较链:

       public int compareTo(Foo that) {
         return ComparisonChain.start()
             .compare(this.aString, that.aString)
             .compare(this.anInt, that.anInt)
             .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
             .result();
       }
    

    请看这里:link to docs

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-13
      相关资源
      最近更新 更多