Compare version strings in groovy

2020-01-29 15:14发布

Hey I have created a Groovy script that will extract the version numbers of some folder. I would then like to compare the version numbers and select the highest.

I got my script to run through the dir folder and I then get the versions in this format: 02.2.02.01

So I could get something like this:

  • 02.2.02.01
  • 02.2.02.02
  • 02.2.03.01

I don't have them as a list but like this:

baseDir.listFiles().each { file -> 
  def string = file.getName().substring(5, 15)
  // do stuff
}

Also I have tested that Groovy could compare them with the > operator and it can! But now I need to select the one with the highest version

11条回答
乱世女痞
2楼-- · 2020-01-29 15:15

This appears to work

String mostRecentVersion(List versions) {
  def sorted = versions.sort(false) { a, b -> 

    List verA = a.tokenize('.')
    List verB = b.tokenize('.')

    def commonIndices = Math.min(verA.size(), verB.size())

    for (int i = 0; i < commonIndices; ++i) {
      def numA = verA[i].toInteger()
      def numB = verB[i].toInteger()
      println "comparing $numA and $numB"

      if (numA != numB) {
        return numA <=> numB
      }
    }

    // If we got this far then all the common indices are identical, so whichever version is longer must be more recent
    verA.size() <=> verB.size()
  }

  println "sorted versions: $sorted"
  sorted[-1]
}

Here is an inadequate set of tests. You should add some more.

assert mostRecentVersion(['02.2.02.01', '02.2.02.02', '02.2.03.01']) == '02.2.03.01' 
assert mostRecentVersion(['4', '2']) == '4'
assert mostRecentVersion(['4.1', '4']) == '4.1'
assert mostRecentVersion(['4.1', '5']) == '5'

Run this code and the tests in the Groovy console to verify that it works

查看更多
三岁会撩人
3楼-- · 2020-01-29 15:21

Here my solution:

def availVersion = "1.5.0.2"
def ownVersion   = "2.6.0.1"

def availTokens = availVersion.split('\\.')
def ownTokens   = ownVersion.split('\\.')

def availSize   = availTokens.size()
def ownSize     = ownTokens.size()

def maxSize     = Math.max(availSize, ownSize)

for (int i = 1; i <= maxSize; i++) {
    def availItem = ((i <= availSize) ? availTokens[i - 1] : 0)
    def ownItem    = ((i <= ownSize)  ? ownTokens[i - 1]   : 0)

    print "Avail: ${availItem} -> Own: ${ownItem}\n"

    if ((ownItem > availItem) || ( (i == maxSize) && (ownItem >= availItem) )) {
        print "Upgrade NOT needed.\n"
        return
    }
}

print "Upgrade needed!\n"
查看更多
Viruses.
4楼-- · 2020-01-29 15:22

If anyone is using Grails (e.g. Grails 2.2.3), I think VersionComparator already provides exactly what we need.

If you are not using Grails, you can always Google the source code of this class.

Example of working tests:

import org.codehaus.groovy.grails.plugins.VersionComparator

assert ['1.13.4', '1.4.5'].sort( new VersionComparator() ) == ['1.4.5', '1.13.4']
assert ['3.1.20', '3', '3.0.1', '3.1'].sort( new VersionComparator() ) == ['3', '3.0.1', '3.1', '3.1.20']
assert ['02.2.02.02', '02.2.03.01', '02.2.02.01'].sort( new VersionComparator() ) == ['02.2.02.01', '02.2.02.02', '02.2.03.01']
assert ['4', '2'].sort( new VersionComparator() ) == ['2', '4']
assert ['4.1', '4'].sort( new VersionComparator() ) == ['4', '4.1']
assert ['4.1', '5'].sort( new VersionComparator() ) == ['4.1', '5']

assert new VersionComparator().compare( '1.13.4', '1.4.5' ) > 0
assert new VersionComparator().compare( '1.4.5', '1.13.4' ) < 0

Hope this helps.

查看更多
手持菜刀,她持情操
5楼-- · 2020-01-29 15:27

Here's a slightly modified version of Nikita's contribution:

List versions = [ '02.2.02.01', '02.2.02.02', '02.2.03.01']
String mostRecentVersion = versions.sort {a, b ->
  def a1 = a.tokenize('.')*.toInteger(), b1 = b.tokenize('.')*.toInteger()   

  for (i in 0..<[a1.size(), b1.size()].min()){      
    if (a1[i] != b1[i]) {
      return a1[i] <=> b1[i]   
    }
  }
}[-1]

assert mostRecentVersion == '02.2.03.01'
查看更多
狗以群分
6楼-- · 2020-01-29 15:31
String maxVersion(versions) {
    versions.max { a, b ->
        List verA = a.tokenize('.')
        List verB = b.tokenize('.')
        def commonIndices = Math.min(verA.size(), verB.size())
        for (int i = 0; i < commonIndices; ++i) {
            def numA = verA[i].toInteger()
            def numB = verB[i].toInteger()
            if (numA != numB) {
                return numA <=> numB
            }
        }
        verA.size() <=> verB.size()
    }
}
查看更多
仙女界的扛把子
7楼-- · 2020-01-29 15:32

If we're going for the shortest answer, this must come close ;-)

String mostRecentVersion( List versions ) {
  versions.sort( false ) { a, b ->
    [a,b]*.tokenize('.')*.collect { it as int }.with { u, v ->
      [u,v].transpose().findResult{ x,y-> x<=>y ?: null } ?: u.size() <=> v.size()
    }
  }[-1]
}
查看更多
登录 后发表回答