编写一个基于多个字段进行排序的比较器

时间:2016-01-18 22:40:23

标签: java sorting java-7

我有3个数据字段,我们将它们命名为Field 1, Field 2, Field 3

现在让我说我有这些价值观:

Field 1  Field 2  Field 3
    1       3        4
    2       3        3
    3       3        5
    4       2        5

如何编写一个比较器,按比例排序Field 1,如果Field 2相等,则它将按降序排序Field 3。结果应该是这样的:

Field 1  Field 2  Field 3
    1       3        5
    2       3        4
    3       3        3
    4       2        5

我可能需要交换价值,但这没关系。

3 个答案:

答案 0 :(得分:3)

编辑:我误解了这个问题。该解决方案对字段1进行排序,然后是字段2,然后是字段3.这不是OP正在寻找的。

我怀疑你有一个包含这三个字段的Java对象。我假设他们可以通过getter访问。我还假设你的对象存储在某种List中。

您尚未指定所使用的Java版本,因此我将使用Java 8解决方案。这可以与早期版本的Java一起使用,但它会更加冗长。

    List<MyObject> myObjects = Arrays.asList(new MyObject(1, 2, 3),
                                             new MyObject(0, 1, 2),
                                             new MyObject(1, 1, 1),
                                             new MyObject(1, 1, 0),
                                             new MyObject(1, 2, 1));
    List<MyObject> sortedList = myObjects.stream()
                                         .sorted(Comparator.comparing(MyObject::getField1)
                                                           .thenComparing(MyObject::getField2)
                                                           .thenComparing(MyObject::getField3))
                                         .collect(Collectors.toList());

    System.out.println(sortedList);

该程序输出

[0-1-2, 1-1-0, 1-1-1, 1-2-1, 1-2-3]

此解决方案使用Java 8 Stream API和sorted()方法,可以轻松对Stream进行排序。排序是通过使用Comparator实现的,Comparator是一个简单的类,可以确定两个实例中哪一个比另一个实例“更大”。

由于Comparator.comparing()方法,创建基于字段比较实例的Comparator非常简单。基于多个字段进行比较是使用.thenComparing()链接返回的import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; public class MyObject { private int field1; private int field2; private int field3; public MyObject(int field1, int field2, int field3) { this.field1 = field1; this.field2 = field2; this.field3 = field3; } public int getField1() { return field1; } public int getField2() { return field2; } public int getField3() { return field3; } @Override public String toString() { return field1 + "-" + field2 + "-" + field3; } public static void main(String[] args) { List<MyObject> myObjects = Arrays.asList(new MyObject(1, 2, 3), new MyObject(0, 1, 2), new MyObject(1, 1, 1), new MyObject(1, 1, 0), new MyObject(1, 2, 1)); List<MyObject> sortedList = myObjects.stream() .sorted(Comparator.comparing(MyObject::getField1) .thenComparing(MyObject::getField2) .thenComparing(MyObject::getField3)) .collect(Collectors.toList()); System.out.println(sortedList); } } 的简单过程。

Java 8方法引用用于引用字段的getter。

完整代码:

# (Please note these are statistical summaries, not actual data sets)
x1  = list(stats = matrix(c(1,2,3,4,5)), n = 5)
x2  = list(stats = matrix(c(4,5,6,7,8)), n = 10)
x3  = list(stats = matrix(c(3,4,5,6,7)), n = 15)
x4  = list(stats = matrix(c(2,3,4,5,6)), n = 20)
x5  = list(stats = matrix(c(5,6,7,8,9)), n = 25)

xx1 = list(stats = matrix(c(1.5,2,3,4,4.5)), n = 5)
xx2 = list(stats = matrix(c(4.5,5,6,7,7.5)), n = 10)
xx3 = list(stats = matrix(c(3.5,4,5,6,6.5)), n = 15)
xx4 = list(stats = matrix(c(2.5,3,4,5,5.5)), n = 20)
xx5 = list(stats = matrix(c(5.5,6,7,8,8.5)), n = 25)


## gather up the data
ll <- mget(ls(pattern = '^x\\d'))
l1 <- list(stats = do.call('cbind', lapply(ll, '[[', 1)),
           n = unlist(lapply(ll, '[[', 2)))

ll <- mget(ls(pattern = 'xx\\d'))
l2 <- list(stats = do.call('cbind', lapply(ll, '[[', 1)),
           n = unlist(lapply(ll, '[[', 2)))

## plot
par(mfrow = c(2, 1), mar = c(2,5,1,1))
bxp(l1, ylab = 'x values', xaxt = 'n')

par(mar = c(2,5,0,1)) ## keep space for group labels
bxp(l2, ylab = 'xx values', xaxt = 'n')
mtext(at = 1:5, side = 1, text = paste('Group', 1:5), line = .5)

答案 1 :(得分:1)

我会分两部分来做。第1部分将基于字段1进行排序。

第2部分将涉及创建一个映射(HashMap),其中字段2的值作为映射到字段3值的二进制堆(PriorityQueue)的键,按相反顺序排序。然后,我会迭代原始数组,并将字段3替换为字段2堆顶部的元素。

答案 2 :(得分:0)

在阅读了对早期答案的回复之后,我认为你是在采用两次通过方式之后。首先,您要按第一个字段对对象列表进行排序。然后你想回到集合中,如果两个项目具有相同的字段2,我们按字段3排序。

所以这是最简单的方法,使用两个不同的比较器对集合进行两次排序,第一个按字段1排序:

@Override
public int compare(MyObject o1, MyObject o2) {
    return Integer.compare(o1.getFieldOne(), o2.getFieldOne());
}

第二个仅在第二个字段相等时按字段三进行排序

    @Override
    public int compare(MyObject o1, MyObject o2) {
        int secondFieldComparison = Integer.compare(o1.getFieldTwo(), o2.getFieldTwo());
        if (secondFieldComparison == 0) {
            return Integer.compare(o1.getFieldThree(), o2.getFieldThree());
        } else {
            return 0;
        }
    }