How to do smart sort in groovy? [duplicate] - sorting

I have a list of version numbers like,
Versions = [0.0.10, 0.0.11, 0.0.13, 0.0.14, 0.0.15, 0.0.16, 0.0.17, 0.0.18, 0.0.19, 0.0.20, 0.0.21, 0.0.22, 0.0.23, 0.0.24, 0.0.25, 0.0.26, 0.0.27, 0.0.28, 0.0.29, 0.0.3, 0.0.30, 0.0.33, 0.0.34, 0.0.35, 0.0.36, 0.0.37, 0.0.38, 0.0.39, 0.0.4, 0.0.41, 0.0.42, 0.0.43, 0.0.44, 0.0.45, 0.0.46, 0.0.47, 0.0.48, 0.0.49, 0.0.5, 0.0.5-delivery.5, 0.0.50, 0.0.51, 0.0.52, 0.0.53, 0.0.54, 0.0.55, 0.0.56, 0.0.57, 0.0.58, 0.0.59, 0.0.6, 0.0.60, 0.0.61, 0.0.62, 0.0.63, 0.0.64, 0.0.7, 0.0.8, 0.0.9]'
And i need to get the last version (0.0.64), Versions.sort() && Collections.max(Versions) doesn't work for me.
So I developed this function blow
def mostRecentVersion(def versions) {
def lastversion = "0.0.0"
for (def items : versions) {
def version = items.tokenize('-')[0]
def ver = version.tokenize('.')
def lastver = lastversion.tokenize('.')
if (lastver[0].toInteger() < ver[0].toInteger() ){
lastversion = version
}else if(lastver[0].toInteger() == ver[0].toInteger()) {
if (lastver[1].toInteger() < ver[1].toInteger() ){
lastversion = version
}else if(lastver[1].toInteger() == ver[1].toInteger()){
if (lastver[2].toInteger() < ver[2].toInteger() ){
lastversion = version
}
}
}
}
return lastversion }
i'm asking if there is something better,
Thank you for help :)

the idea:
build map with sortable key and original version value, then sort map by keys, then get only values
to create sortable key for each value
split version to digits & not-digit strings array
prepend to each part 0 to have minimum length 3 (assume each number not longer then 3 digits)
join array to string
so, for 0.11.222-dev ->
1. [ '0', '.', '11', '222', '-dev' ]
2. [ '000', '00.', '011', '222', '-dev' ]
3. '00000.011222-dev'
the code
def mostRecentVersion(versions){
return versions.collectEntries{
[(it=~/\d+|\D+/).findAll().collect{it.padLeft(3,'0')}.join(),it]
}.sort().values()[-1]
}
//test cases:
def fullVersions = ['0.0.10', '0.0.11', '0.0.13', '0.0.14', '0.0.15', '0.0.16',
'0.0.17', '0.0.18', '0.0.19', '0.0.20', '0.0.21', '0.0.22', '0.0.23', '0.0.24',
'0.0.25', '0.0.26', '0.0.27', '0.0.28', '0.0.29', '0.0.3', '0.0.30', '0.0.33',
'0.0.34', '0.0.35', '0.0.36', '0.0.37', '0.0.38', '0.0.39', '0.0.4', '0.0.41',
'0.0.42', '0.0.43', '0.0.44', '0.0.45', '0.0.46', '0.0.47', '0.0.48', '0.0.49',
'0.0.5', '0.0.5-delivery.5', '0.0.50', '0.0.51', '0.0.52', '0.0.53', '0.0.54',
'0.0.55', '0.0.56', '0.0.57', '0.0.58', '0.0.59', '0.0.6', '0.0.60', '0.0.61',
'0.0.62', '0.0.63', '0.0.64', '0.0.7', '0.0.8', '0.0.9']
assert mostRecentVersion(fullVersions) == '0.0.64'
assert mostRecentVersion(['0.0.5-delivery.5', '0.0.3', '0.0.5']) == '0.0.5-delivery.5'
assert mostRecentVersion(['0.0.5.5', '0.0.5-delivery.5', '0.0.5']) == '0.0.5.5'

I believe this will work... it also keeps the original version strings around, incase 0.5.5-devel.5 is the latest... It relies on the fact that Groovy will use a LinkedHashMap for the sorted map, so the order will be preserved :-)
def mostRecentVersion(def versions) {
versions.collectEntries {
[it, it.split(/\./).collect { (it =~ /([0-9]+).*/)[0][1] }*.toInteger()]
}.sort { a, b ->
[a.value, b.value].transpose().findResult { x, y -> x <=> y ?: null } ?:
a.value.size() <=> b.value.size() ?:
a.key <=> b.key
}.keySet()[-1]
}
def fullVersions = ['0.0.10', '0.0.11', '0.0.13', '0.0.14', '0.0.15', '0.0.16', '0.0.17', '0.0.18', '0.0.19', '0.0.20', '0.0.21', '0.0.22', '0.0.23', '0.0.24', '0.0.25', '0.0.26', '0.0.27', '0.0.28', '0.0.29', '0.0.3', '0.0.30', '0.0.33', '0.0.34', '0.0.35', '0.0.36', '0.0.37', '0.0.38', '0.0.39', '0.0.4', '0.0.41', '0.0.42', '0.0.43', '0.0.44', '0.0.45', '0.0.46', '0.0.47', '0.0.48', '0.0.49', '0.0.5', '0.0.5-delivery.5', '0.0.50', '0.0.51', '0.0.52', '0.0.53', '0.0.54', '0.0.55', '0.0.56', '0.0.57', '0.0.58', '0.0.59', '0.0.6', '0.0.60', '0.0.61', '0.0.62', '0.0.63', '0.0.64', '0.0.7', '0.0.8', '0.0.9']
assert mostRecentVersion(fullVersions) == '0.0.64'
assert mostRecentVersion(['0.0.5-delivery.5', '0.0.3', '0.0.5']) == '0.0.5-delivery.5'
assert mostRecentVersion(['0.0.5.5', '0.0.5-delivery.5', '0.0.5']) == '0.0.5.5'
Edit:
Made a change so that 0.5.5.5 > 0.5.5-devel.5

Related

Compare time using Laravel

In my Laravel application I want to compare times
If time was greater than 23:30 and less than 6:00 returns true
else return false
$time1 = strtotime('23:30:00');
$time2 = strtotime('06:00:00');
$time3 = strtotime('01:30:00');
if ($time3>=$time1 && $time2>$time1 ) {
var_dump('yes');
}
else {
var_dump('no');
}
I would suggest using Carbon to compare date and datetime values:
$time1 = Carbon::createFromTimeString('23:30:00');
$time2 = Carbon::createFromTimeString('06:00:00');
$time3 = Carbon::createFromTimeString('01:30:00');
if ($time3->gte($time1) && $time2->gt($time1)) {
var_dump('yes');
} else {
var_dump('no');
}
Use Carbon, it has functionality to create from a certain format, with the createFromFormat() method.
$time1 = Carbon::createFromFormat('H:i:s', '23:30:00');
$time2 = Carbon::createFromFormat('H:i:s', '06:00:00');
$time3 = Carbon::createFromFormat('H:i:s', '01:30:00');
Carbon has comparisons in built, with gt() being greater than and lt() being less than. Adding an e to the call as lte() would be less than equals. Or you can be more explicit, look through this section in the documentation.
if ($time3->gte($time1) && $time2->gt($time1)) {
//
}
else {
//
}

How to sort given array list?

list = ["HM00", "HM01", "HM010", "HM011", "HM012", "HM013", "HM014", "HM015", "HM016", "HM017", "HM018", "HM019", "HM02", "HM020", "HM021", "HM022", "HM023", "HM024", "HM025", "HM026", "HM027", "HM028", "HM029", "HM03", "HM030", "HM031", "HM032", "HM033", "HM034", "HM035", "HM036", "HM037", "HM038", "HM039", "HM04", "HM040", "HM041", "HM042", "HM043", "HM044", "HM045", "HM046", "HM047", "HM05", "HM06", "HM07", "HM08", "HM09"]
I want the display the results as ["HM00","HM01","HM002"...] but using sort method it is giving the below results
["HM00", "HM01", "HM010", "HM011", "HM012", "HM013", "HM014", "HM015", "HM016", "HM017", "HM018", "HM019", "HM02"]
If every element has a number at the end
list.sort_by { |item| item.scan(/\d*$/).first.to_i }
match that number at the end, take the first one (because scan gives you an array of results), convert it to an integer
simpler
list.sort_by { |item| item[/\d*$/].to_i }
[] already takes the first match
There is a more general solution that will work with most strings that contain groups of numbers
number = /([+-]{0,1}\d+)/;
strings = [ '2', '-2', '10', '0010', '010', 'a', '10a', '010a', '0010a', 'b10', 'b2', 'a1b10c20', 'a1b2.2c2' ]
p strings.sort_by { |item| [item.split(number).each_slice(2).map {
|x| x.size == 1 ? [ x[0], '0' ] : [ x[0], x[1] ] }].map {|y| ret = y.inject({r:[],x:[]}) { |s, z| s[:r].push [ z[0], z[1].to_r]; s[:x].push z[1].size.to_s; s }; ret[:r] + ret[:x] }.flatten
}
You can adjust number to match the types of numbers you want to use: integers, floating point, etc.
There is some extra code to sort equal numbers by length so that '10' comes before '010'.

Compare keys of array in RUBY

I have this structure:
$ArrayX = [8349310431,8349314513,......]
$ArrayY = [667984788,667987788,......]
$ArrayZ = [148507632380,153294624079,.....]
$range_map = $ArrayX.zip([$ArrayY.map(&:to_i),
$ArrayZ.map(&:to_i)].transpose).sort
puts $range_map ={[8349310431=>[667984788, 148507632380],
8349314513=>[667987788, 153294624079]}
I need the key to be compared with the rest of the keys and if the subtraction between keys is lower than 100, that key to print
I corrected your code also as per your need, and solved further,
$ArrayX = [8349310431,8349314513]
$ArrayY = [667984788,667987788]
$ArrayZ = [148507632380,153294624079]
$range_map = $ArrayX.zip([$ArrayY.map(&:to_i), $ArrayZ.map(&:to_i)].transpose).sort
$ArrayX = [8349310431,8349314513]
=> [8349310431, 8349314513]
$ArrayY = [667984788,667987788]
=> [667984788, 667987788]
$ArrayZ = [148507632380,153294624079]
=> [148507632380, 153294624079]
$range_map = Hash[$ArrayX.zip([$ArrayY.map(&:to_i), $ArrayZ.map(&:to_i)].transpose).sort]
=> {8349310431=>[667984788, 148507632380], 8349314513=>[667987788, 153294624079]}
keys = $range_map.keys
valid_keys = keys.select { |k| keys.detect { |x| (x-k).abs > 100 } }
$range_map.slice(*valid_keys)
If particular key is having difference more than 100 with one of rest of keys then it will be valid for filtering.

how to find value with path x Groovy

please advise how to find and output cust_JiraTaskId. I need the value of cust_JiraTaskId based on the max number of inside node . In this example it'll be 111111.
I managed to find the max externalCode and now i need cust_JiraTaskId value.
<SFOData.cust_JiraReplication>
<cust_HRISId>J000009</cust_HRISId>
<externalCode>7</externalCode>
<cust_JiraTask>
<externalCode>3</externalCode>
<cust_JiraTaskId>12345</cust_JiraTaskId>
</cust_JiraTask>
<cust_JiraTask>
<externalCode>5</externalCode>
<cust_JiraTaskId>111111</cust_JiraTaskId>
</cust_JiraTask>
</SFOData.cust_JiraReplication>
My script is below
// Create an XPath statement to search for the
element or elements you care about:
XPath x;
x = XPath.newInstance("//cust_JiraTask/externalCode");
myElements = x.selectNodes(doc);
String maxvalue = "";
for (Element myElement : myElements) {
if (myElement.getValue() > maxvalue)
{
maxvalue = myElement.getValue();
}
}
props.setProperty("document.dynamic.userdefined.externalCode", maxvalue);
thanks for help.
This works for me with Groovy 2.4.5:
def xml = """
<SFOData.cust_JiraReplication>
<cust_HRISId>J000009</cust_HRISId>
<externalCode>7</externalCode>
<cust_JiraTask>
<externalCode>3</externalCode>
<cust_JiraTaskId>12345</cust_JiraTaskId>
</cust_JiraTask>
<cust_JiraTask>
<externalCode>5</externalCode>
<cust_JiraTaskId>111111</cust_JiraTaskId>
</cust_JiraTask>
</SFOData.cust_JiraReplication>
"""
def xs = new XmlSlurper().parseText(xml)
def nodes = xs.cust_JiraTask.cust_JiraTaskId
def maxNode = nodes.max { it.text() as int }
assert 111111 == maxNode.text() as int

Perl to Ruby conversion (multidimensional arrays)

I'm just trying to get my head around a multidimensional array creation from a perl script i'm currently converting to Ruby, I have 0 experience in Perl, as in i opened my first Perl script this morning.
Here is the original loop:
my $tl = {};
for my $zoom ($zoommin..$zoommax) {
my $txmin = lon2tilex($lonmin, $zoom);
my $txmax = lon2tilex($lonmax, $zoom);
# Note that y=0 is near lat=+85.0511 and y=max is near
# lat=-85.0511, so lat2tiley is monotonically decreasing.
my $tymin = lat2tiley($latmax, $zoom);
my $tymax = lat2tiley($latmin, $zoom);
my $ntx = $txmax - $txmin + 1;
my $nty = $tymax - $tymin + 1;
printf "Schedule %d (%d x %d) tiles for zoom level %d for download ...\n",
$ntx*$nty, $ntx, $nty, $zoom
unless $opt{quiet};
$tl->{$zoom} = [];
for my $tx ($txmin..$txmax) {
for my $ty ($tymin..$tymax) {
push #{$tl->{$zoom}},
{ xyz => [ $tx, $ty, $zoom ] };
}
}
}
and what i have so far in Ruby:
tl = []
for zoom in zoommin..zoommax
txmin = cm.tiles.xtile(lonmin,zoom)
txmax = cm.tiles.xtile(lonmax,zoom)
tymin = cm.tiles.ytile(latmax,zoom)
tymax = cm.tiles.ytile(latmin,zoom)
ntx = txmax - txmin + 1
nty = tymax - tymin + 1
tl[zoom] = []
for tx in txmin..txmax
for ty in tymin..tymax
tl[zoom] << xyz = [tx,ty,zoom]
puts tl
end
end
end
The part i'm unsure of is nested right at the root of the loops, push #{$tl->{$zoom}},{ xyz => [ $tx, $ty, $zoom ] };
I'm sure this will be very simple for a seasoned Perl programmer, thanks! `
The Perl code is building up a complex data structure in $tl -- hash, array, hash, array:
$tl{$zoom}[i]{xyz}[j] = $tx # j = 0
$tl{$zoom}[i]{xyz}[j] = $ty # j = 1
$tl{$zoom}[i]{xyz}[j] = $zoom # j = 2
So I think the key line in your Ruby code should be like this:
tl[zoom] << { 'xzy' => [tx,ty,zoom] }
Note also that the root item ($tl) refers to a hash in the Perl code, while your Ruby code initializes it to be an array. That difference might cause problems for you, depending on the values that $zoom takes.

Resources