【问题标题】:Groovy list.sort by first, second then third elementsGroovy list.sort 按第一个,第二个,然后是第三个元素
【发布时间】:2009-09-23 18:00:15
【问题描述】:

我有一个很好的列表,即

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] } 开始,但这仅对第一个元素进行排序。你怎么完成的?

谢谢

【问题讨论】:

标签: sorting groovy


【解决方案1】:

您应该能够以相反的顺序遍历所需的排序:

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 operator, ?: 按顺序链接,当前一个相等时,它将推迟到下一个比较(并且&lt;=&gt; 返回0):

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

【讨论】:

  • 它应该——理论上——可能——你为什么不检查一下?正确答案是最后一个,你可以去掉括号:list.sort{ a,b -&gt; a[0] &lt;=&gt; b[0] ?: a[1] &lt;=&gt; b[1] ?: a[2] &lt;=&gt; b[2] }
【解决方案2】:

如果你想对任意长度的数组进行排序(虽然是同质的),你可以使用它,它会一次性完成:

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]]

【讨论】:

    【解决方案3】:

    这是另一种使用 Groovy 的 SpaceshipElvis 运算符的方法:

    ​def list = [[2, 0, 1], [1, 5, 2], [1, 0, 3]]
    
    list.sort { a, b ->
       a[0] <=> b[0] ?: a[1] <=> b[1] ?: a[2] <=> b[2]
    }
    
    assert list == [[1, 0, 3], [1, 5, 2], [2, 0, 1]]​
    

    来源:Groovier way of sorting over multiple fields in a list of maps in groovy

    【讨论】:

      【解决方案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]]
      

      【讨论】:

        【解决方案5】:

        使用 Groovy 方式,不管子列表的大小:

        ll2.sort { l1, l2 ->
          e1e2 = [l1, l2].transpose().find { e1, e2 ->
              e1 != e2
          }
          e1e2 ? e1e2[0] <=> e1e2[1] : 0
        }
        

        【讨论】:

        • 它看起来很有希望,但它在 NPE 上失败了,例如 [1,1],[1,1] - 但幸运的是修复很容易。
        • 谢谢。更新了更简洁的语法。
        【解决方案6】:

        这是我想出的,不是我想的最时髦的方式..

        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]);
            }
        }
        

        【讨论】:

          【解决方案7】:

          你可以在一行中完成:

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

          【讨论】:

            【解决方案8】:

            我知道我参加聚会很晚了,但我想要一种方法来按多个键、asc 或 desc 分别为每个字段排序。我想出了这个似乎可行的方法:

            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]]
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-03-11
              • 1970-01-01
              • 2011-06-14
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多