以不寻常的方式在Groovy中对列表进行排序

时间:2012-03-15 11:37:21

标签: sorting groovy

我有一个列表,比方说[Cat, Dog, Cow, Horse],我希望按以下方式排序

  • 如果Cat在列表中,它应该首先出现
  • 如果Cow在列表中,它应该是第二个
  • 其余元素应按字母顺序排列。

有关如何在Groovy中完成此操作的任何建议吗?

6 个答案:

答案 0 :(得分:7)

蒂姆的回答非常聪明。我个人更喜欢使用列表操作,因为它生成的代码稍微容易阅读。

def highPriority = [ 'Cat', 'Cow' ]

def list = [ 'Armadillo', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cow', 'Cat' ]

def remainder = ( list - highPriority ).sort()

list.retainAll( highPriority )

list.sort{ highPriority.indexOf( it ) } + remainder

那会给你两次牛。如果你不想重复,使用intersect非常简单。

def highPriority = [ 'Cat', 'Cow' ]

def list = [ 'Armadillo', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cow', 'Cat' ]

list.intersect( highPriority ).sort{ highPriority.indexOf( it ) } + ( list - highPriority ).sort()

答案 1 :(得分:6)

这应该这样做:

// Define our input list
def list = [ 'Armadillo', 'Cat', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cow' ]

// Define a closure that will do the sorting
def sorter = { String a, String b, List prefixes=[ 'Cat', 'Cow' ] ->
  // Get the index into order for a and b
  // if not found, set to being Integer.MAX_VALUE
  def (aidx,bidx) = [a,b].collect { prefixes.indexOf it }.collect {
    it == -1 ? Integer.MAX_VALUE : it
  }
  // Compare the two indexes.
  // If they are the same, compare alphabetically
  aidx <=> bidx ?: a <=> b
}

// Create a new list by sorting using our closure
def sorted = list.sort false, sorter

// Print it out
println sorted

打印:

[Cat, Cow, Cow, Armadillo, Dog, Horse, Zebra]

我评论它试图解释它所采取的每一步。通过在sorter闭包上添加默认前缀项作为可选参数,这意味着我们可以执行以下操作来更改默认值:

// Use Dog, Zebra, Cow as our prefix items
def dzc = list.sort false, sorter.rcurry( [ 'Dog', 'Zebra', 'Cow' ] )
println dzc

然后将列表打印为:

[Dog, Zebra, Cow, Cow, Armadillo, Cat, Horse]

答案 2 :(得分:2)

这是另一种让我感觉更简单的选择:

// smaller values get sorted first
def priority(animal) {
    animal in ['Cat', 'Cow'] ? 0 : 1
}

def list = [ 'Armadillo', 'Cat', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cow' ]

def sorted = list.sort{ a, b -> priority(a) <=> priority(b) ?: a <=> b }

assert sorted == ['Cat', 'Cow', 'Cow', 'Armadillo', 'Dog', 'Horse', 'Zebra']

答案 3 :(得分:1)

如果您没有重复的元素,可以试试这个:

def highPriority = [ 'Cat', 'Cow' ]
def list = [ 'Armadillo', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cat' ]
highPriority + list.minus(highPriority).sort()

答案 4 :(得分:0)

启发tomas' answer

def highPriority = [ 'Cat', 'Cow' ]
def list = [ 'Armadillo', 'Cat', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cow' ]

// Group animals by priority.
def groups = list.groupBy { it in highPriority ? it : 'rest' }
// High priority animals are sorted by priority and the rest alphabetically.
def sorted = highPriority.collectMany { groups[it] } + groups['rest'].sort()

assert sorted == ['Cat', 'Cow', 'Cow', 'Armadillo', 'Dog', 'Horse', 'Zebra']

groups变量类似于[rest:[Armadillo, Dog, Zebra, Horse], Cat:[Cat], Cow:[Cow, Cow]]

另一个可能不那么强大的解决方案可能是:

def sorted = list.sort(false) { 
    def priority = highPriority.indexOf(it)
    if (priority == -1) priority = highPriority.size()
    // Sort first by priority and then by the value itself
    "$priority$it"
}

它在"2Armadillo""0Cat"等字符串排序的意义上不那么强大,如果你有9个或更多高优先级的动物,它就不会起作用(因为{{1}如果Groovy提供某种类似的元组类型(例如Python's tuples)会很酷,所以不是将"10Alpaca" < "9Eel"作为可比较的键返回,而是可以返回元组"$priority$it"

答案 5 :(得分:0)

这个问题已经很老了,但今天我发现Groovy有一个相当无证的OrderBy比较器,可用于这种情况:

def highPriority = ['Cow', 'Cat']
def list = ['Armadillo', 'Cat', 'Dog', 'Cow', 'Zebra', 'Horse', 'Cow']

def sorted = list.sort new OrderBy([{ -highPriority.indexOf(it) }, { it }])

assert sorted == ['Cat', 'Cow', 'Cow', 'Armadillo', 'Dog', 'Horse', 'Zebra']

OrderBy比较器首先使用highPriority列表中的索引来比较动物(因此不高优先级的动物(即索引-1)被移动到列表的后面)如果索引相等,则通过标识函数{it}对它们进行比较,标识函数{{1}}作为动物是字符串,按字母顺序对它们进行排序。