Groovy列表按第一、第二和第三个元素排序

30

我有一个Groovy的列表,其中包含多个列表。

list = [[2, 0, 1], [1, 5, 2], [1, 0, 3]]

我想按照第一个元素的顺序,然后是第二个,再然后是第三个来排序。

期望结果

assert list == [[1, 0, 3], [1, 5, 2], [2, 0, 1]]

我最初尝试使用list = list.sort{ a,b -> a[0] <=> b[0] }进行排序,但这只能排序第一个元素。如何完成排序呢?

谢谢


请查看此贴https://dev59.com/82445IYBdhLWcg3wZJYn - LukeSolar
8个回答

36

您应该能够以相反的顺序迭代所需的排序:

list = [[2, 0, 1], [1, 5, 2], [1, 0, 3]]

list = list.sort{ a,b -> a[2] <=> b[2] }
list = list.sort{ a,b -> a[1] <=> b[1] }
list = list.sort{ a,b -> a[0] <=> b[0] }

assert list == [[1, 0, 3], [1, 5, 2], [2, 0, 1]]

每个人都应该覆盖上一个,只要足够使组合排序保持不变。


你也可以使用Elvis运算符?:按顺序链接它们,当前一个相等时(并且<=>返回0)将推迟到下一个比较:

list.sort { a,b -> a[0] <=> b[0] ?: a[1] <=> b[1] ?: a[2] <=> b[2] }

5
理论上,它应该有可能——为什么你不直接检查一下呢?正确答案是最后一个,并且你可以去掉括号:list.sort{ a,b -> a[0] <=> b[0] ?: a[1] <=> b[1] ?: a[2] <=> b[2] } - Tobia

9

如果你想对任意长度的(同质)数组进行排序,你可以使用这个方法,在一次遍历中完成排序:

def list = [[2, 0, 1], [1, 5, 2], [1, 0, 3]]

list.sort { a, b -> 
    for (int i : (0..<a.size())) {
        def comparison = (a[i] <=> b[i])
        if (comparison) return comparison
    } 
    return 0
}

assert list == [[1, 0, 3], [1, 5, 2], [2, 0, 1]]

7

4
你可以使用kobo-commons的CollectionUtils库。

https://github.com/kobo/kobo-commons/wiki/sort-by-multiple-keys

import org.jggug.kobo.commons.lang.CollectionUtils

CollectionUtils.extendMetaClass()


list = [[2, 0, 1], [1, 5, 2], [1, 0, 3]]
list = list.sort{ [ it[0], it[1], it[2] ]} // sort by multiple keys
assert list == [[1, 0, 3], [1, 5, 2], [2, 0, 1]]

list2 = [ [name:"a", age:13], [name:"a",age:15], [name:"b", age:13] ]
list2 = list2.sort{[it.name, it.age] } // sort by name and age
assert list2 == [[name:"a", age:13], [name:"a", age:15], [name:"b", age:13]]

2
无论子列表的大小如何,都可以按照 Groovy 的方式完成:
ll2.sort { l1, l2 ->
  e1e2 = [l1, l2].transpose().find { e1, e2 ->
      e1 != e2
  }
  e1e2 ? e1e2[0] <=> e1e2[1] : 0
}

看起来很有希望,但在例如[1,1],[1,1]上出现了NPE错误 - 但幸运的是,修复很容易。 - askucins
谢谢。已更新为更清晰的语法。 - BahmanM

0

我知道我来晚了,但我想找到一种按多个键排序的方法,可以分别按升序或降序对每个字段进行排序。我想出了这种方法,似乎可以实现:

public static sortObjectArray(def objects, Map sortFields){
    objects.sort{a,b->
        int matches = 0
        for(def entry in sortFields){

            if(entry.value == 'asc'){
                matches = (a[entry.key] <=> b[entry.key]).toInteger()
            }else{
                matches = (b[entry.key] <=> a[entry.key]).toInteger()
            }

            if(matches != 0){
                break
            }
        }

        return matches
    }
}

它允许传递一个对象列表和一个映射,对象列表将按照映射的键进行排序,根据映射条目的值,可以是降序或升序。例如:

ArrayList<Map> objects = [
        [field1:1,field2:2,field3:2],
        [field1:1,field2:1,field3:1],
        [field1:1,field2:2,field3:1],
]

println sortObjectArray(objects,[field1:'asc',field2: 'desc',field3: 'asc'])

输出:

[[field1:1, field2:2, field3:1], [field1:1, field2:2, field3:2], [field1:1, field2:1, field3:1]]

0

这是我想出来的,可能不是最棒的方式..

list = list.sort{ a,b -> 
    if(a[0].compareTo(b[0]) == 0) {
        if(a[1].compareTo(b[1]) == 0) {
            return a[2].compareTo(b[2]);
        } else {
            return a[1].compareTo(b[1]);
        }
    } else {
        return a[0].compareTo(b[0]);
    }
}

0

你可以用一行代码实现:

list.sort { String.format('%010d%010d%010d', it[0], it[1], it[2]) }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接