Groovy словарь карта - как сортировать по значению ключа карты - если значение в формате x.x.x.x - числовая сортировка значения версии с. голец - PullRequest
0 голосов
/ 29 августа 2018

У меня есть следующий словарь ака MAP на Groovy.

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

Я пытаюсь отсортировать эту карту в соотв. ключ свойств = значение PIPELINE_VERSION в формате 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

Ответы [ 4 ]

0 голосов
/ 30 августа 2018

Учитывая это:

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]
0 голосов
/ 29 августа 2018

Ниже должно работать (при условии, что формат 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)
0 голосов
/ 29 августа 2018

Это однострочное решение сработало.

Для меньшего примера!

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 (однострочное) для сложной структуры (подсказка из ответа Дмахапатро): то есть карта> содержащая массив> содержащая другую карту для 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()

ПРИМЕЧАНИЕ. Приведенное выше решение и другие ответы до сих пор будут иметь место только в том случае, если первые 3 набора цифр PIPELINE равны 1,0,0, т. Е. Определяется только наибольшее число на основе набора 4-х цифр (.last ()). Было бы интересно использовать подобную однострочную строку, чтобы найти наибольшее значение PIPELINE_VERSION, которое на самом деле охватывает все 4 или N нет. наборов цифр.

0 голосов
/ 29 августа 2018
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]
...