【问题标题】:Groovy dictionary map - how to sort according to a map's key's value - if the value is in x.x.x.x format - numberically sort version value with . charGroovy 字典映射 - 如何根据映射的键值排序 - 如果值是 x.x.x.x 格式 - 使用 .字符
【发布时间】:2018-08-29 17:05:27
【问题描述】:

我在 Groovy 中有以下字典,即 MAP。

list = [
   [ 
     name:ProductA-manifest-file.json, 
     path:ProductA, 
     properties: [
                   [
                     key:release, 
                     value:RC1.0
                   ], 
                   [ key:PIPELINE_VERSION, 
                     value:1.0.0.11
                   ]
                ], 
    repo:some-generic-repo-local, 
   ],
   [ 
     name:ProductA-manifest-file.json, 
     path:ProductA, 
     properties: [
                   [
                     key:release, 
                     value:RC1.0
                   ], 
                   [ key:PIPELINE_VERSION, 
                     value:1.0.0.75
                   ]
                ], 
    repo:some-generic-repo-local, 
   ],
   [ 
     name:ProductA-manifest-file.json, 
     path:ProductA, 
     properties: [
                   [
                     key:release, 
                     value:RC1.0
                   ], 
                   [ key:PIPELINE_VERSION, 
                     value:1.0.0.1104
                   ]
                ], 
    repo:some-generic-repo-local, 
   ],
   [
    more similar entries here containing 
   ],
   [
    more similar entries here
   ]
]  

我正在尝试对这张地图进行排序。 properties's key = PIPELINE_VERSION's value,格式为x.x.x.x,即4位设置大小写。

我尝试了以下命令,但它没有给我包含 1.0.0.1104 作为 PIPELINE_VERSION 的条目。它给了我 1.0.0.75(这似乎是某种字符串类型的排序。

// Sort the list entries acc. to pipeline version
def sortedList = list.sort { it.properties.PIPELINE_VERSION.value }
println "###### sortedList" + sortedList
println "\n^^^^\n"
println sortedList.last()  // this should return me the entry which contains 1.0.0.1104 but I'm getting 1.0.0.75
 }

还尝试将 .toInteger() 用作def sortedList = list.sort { it.properties.PIPELINE_VERSION.toInteger().value },但没有奏效,出现错误。

17:07:22 Caught: groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.toInteger() is applicable for argument types: () values: []
17:07:22 Possible solutions: toUnique(), toUnique()
17:07:22 groovy.lang.MissingMethodException: No signature of method: java.util.ArrayList.toInteger() is applicable for argument types: () values: []
17:07:22 Possible solutions: toUnique(), toUnique()

试过了:list.sort {it.value.tokenize('.').last()} 也没有用。

较小的例子是:

map = ['a':'1.0.0.11', d:'1.0.0.85', 'b':'1.0.0.1104', 'c':"1.0.0.75"]

println " before sorting : " + map

//map = map.sort {it.value }   // this doesn't work if the value is not a pure number format aka x.x.x. format ok lets try the following    
map = map.sort {it.value.tokenize('.').last()} // cool that didn't work either

println " after  sorting : " + map

问题:

  1. 如何获取具有最高 PIPELINE_VERSION 值的条目?
  2. 如何获取第 N 个数组索引条目,它的值包含最高的 PIPELINE_VERSOIN。
  3. 如何处理 N 号。数字集集案例?即 1.0.0 或 1.2 或 1.0.0.12 或 1.4.1.9.255

【问题讨论】:

  • :) 差不多,但不准确,因为它没有处理相同的结构,而且解决方案看起来很长。下面提到的一个 dmahapatro 看起来更干净,但我试图在我的回答中让它更干净(单线)。
  • 是的,距离不够近,无法关闭????希望它有助于比较版本

标签: arrays sorting dictionary groovy version


【解决方案1】:

下面应该可以工作(假设格式 X.X.X.X 总是将 X 作为数字)

def sortClosure = { a, b ->

  // Extract the pattern
  def extract = { 
    it.properties.find { it.key == 'PIPELINE_VERSION' }?.value?.tokenize(/./) 
  }

  // Transpose the numbers to compare
  // gives [[1,1], [0,0], [0,0], [11, 1104]] for example
  def transposed = [extract(a), extract(b)].transpose()

  // Then compare the first occurrence of non-zero value (-1 or 1)
  def compareInt = transposed.collect { 
    it[0].toInteger() <=> it[1].toInteger() 
  }.find()

  compareInt ?: 0
}

list.sort(sortClosure)

【讨论】:

  • 感谢您的提示。我接受了这个作为答案,即使我使用你的提示将它变成了一个单行。
  • 你能解释一下那行中的? 字符是什么吗?此外,如果我们能以某种方式获得涵盖所有 4 或 N 的最高 PIPELINE_VERSION。没有。的数字集。现在,它只寻找第 4 位数字集。
  • 这实际上是最好的解决方案,因为它涵盖了所有情况,即它将涵盖 PIPELINE_VERSION 中的所有 N 位数集
  • 一个发现:用这一行代替上面那一行会更好。 transposed.collect { it[0].toInteger() &lt;=&gt; it[1].toInteger() }.find() ?: 0
  • 是的,这也是有道理的。这将避免对空列表执行 getAt() 操作。
【解决方案2】:

这种单线解决方案奏效了。

对于较小的例子!

def versions = ['a':'1.0.0.11', d:'1.0.0.85', 'b':'1.0.0.1104', 'c':"1.0.0.75"]
map = map.sort {it.value.tokenize('.').last().toInteger() }

好的,找到了复杂结构的 shenzi(单线)解决方案(来自 dmahapatro 的回答提示): 即地图 > 包含数组 > 包含 PIPELINE_VERSION 的另一个地图。

println "\n\n before sorting : " + list

list = list.sort {it.properties.find { it.key == 'PIPELINE_VERSION' }?.value?.tokenize('.').last().toInteger() }

println " after  sorting : " + list
println "\n\n The last entry which contains the sorted shenzi is: " + map.last()

注意:到目前为止,上述解决方案和其他答案仅在 PIPELINE 前 3 位数字集为 1.0.0 时才有效,即它仅根据第 4 位数字集 (.last()) 决定最高数字。使用类似的单线查找实际上涵盖所有 4 或 N 的最高 PIPELINE_VERSION 会很有趣。数字集。

【讨论】:

  • 注意:使用.toLong() 比使用.toInteger() 更好
【解决方案3】:
def versions = ['a':'1.0.0.11', d:'1.0.0.85', 'b':'1.0.0.1104', 'c':"1.0.0.75"]
//sort:
def sorted = versions.sort{ (it.value=~/\d+|\D+/).findAll() }

结果:

[a:1.0.0.11, c:1.0.0.75, d:1.0.0.85, b:1.0.0.1104]

【讨论】:

  • def sorted = versions.sort {it.value.tokenize('.').last().toInteger() } 更干净。在我的嵌套原始地图中,它是一个包含一个数组作为属性值的 MAP,其中包含字典/地图数组。现在正在努力让它发挥作用。
【解决方案4】:

鉴于此:

def map = ['a':'1.0.0.11', d:'1.0.0.85', 'b':'1.0.0.1104', 'c':"1.0.0.75"]

map = map.sort { a, b ->
    compareVersion(a.value, b.value)
}

目标变成编写满足这些(不完整)测试的compareVersion 函数:

assert 0  == compareVersion('1.0.0.0', '1.0.0.0')
assert 1  == compareVersion('1.1.0.0', '1.0.0.0')
assert -1 == compareVersion('1.1.0.0', '1.2.0.0')
assert 1  == compareVersion('1.1.3.0', '1.1.2.0')
assert 1  == compareVersion('1.1.4.1104', '1.1.4.11')

这是一种实现。它不是最短的,但风格相当“Groovy”:

//
// e.g. a = '1.0.0.11', b = '1.0.0.85'
//
def compareVersion = { a, b ->
    // e.g. [1, 0, 0, 11]
    def listA = a.tokenize('.').collect { it as int }

    // e.g. [1, 0, 0, 85]
    def listB = b.tokenize('.').collect { it as int }

    // e.g. [0, 0, 0, -1]
    def compareList = [listA, listB].transpose().collect { it[0] <=> it[1] }

    // return first non-zero value in compareList, or 0 if there are none
    compareList.inject(0) { result, item ->
        (result) ?: item
    }
}

原始地图的输出,并排序:

$ groovy Q.groovy 
 before sorting : [a:1.0.0.11, d:1.0.0.85, b:1.0.0.1104, c:1.0.0.75]
 after  sorting : [a:1.0.0.11, c:1.0.0.75, d:1.0.0.85, b:1.0.0.1104]

【讨论】:

    猜你喜欢
    • 2021-08-02
    • 1970-01-01
    • 1970-01-01
    • 2021-01-24
    • 2020-10-04
    • 1970-01-01
    • 2011-10-18
    • 1970-01-01
    • 2011-12-27
    相关资源
    最近更新 更多