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
The documentation says "delete cannot work with partial keys". What is your recommendation how to solve it. For example create new index, use cycle delete or any way?
You can delete values in a loop using a primary key.
#!/usr/bin/env tarantool
local json = require('json')
local function key_from_tuple(tuple, key_parts)
local key = {}
for _, part in ipairs(key_parts) do
table.insert(key, tuple[part.fieldno] or box.NULL)
end
return key
end
box.cfg{}
box.once('init', function()
box.schema.space.create('s')
box.space.s:create_index('pk')
box.space.s:create_index('sk', {
unique = false,
parts = {
{2, 'number'},
{3, 'number'},
}
})
end)
box.space.s:truncate()
box.space.s:insert{1, 1, 1}
box.space.s:insert{2, 1, 1}
print('before delete')
print('---')
box.space.s:pairs():each(function(tuple)
print(json.encode(tuple))
end)
print('...')
local key_parts = box.space.s.index.pk.parts
for _, tuple in box.space.s.index.sk:pairs({1}) do
local key = key_from_tuple(tuple, key_parts)
box.space.s.index.pk:delete(key)
end
print('after delete')
print('---')
box.space.s:pairs():each(function(tuple)
print(json.encode(tuple))
end)
print('...')
os.exit()
In the example above a common case is handled using key_from_tuple function. Things may be simpler when you know which fields form a primary key. Say, if it is the first field:
for _, tuple in box.space.s.index.sk:pairs({1}) do
box.space.s.index.pk:delete(tuple[1])
end
The new key_def module that was added in tarantool-2.2.0-255-g22db9c264 (not released yet, but availiable from our 2.2 repository) simplifies extracting a key from a tuple, especially in case of json path indexes:
#!/usr/bin/env tarantool
local json = require('json')
local key_def_lib = require('key_def')
box.cfg{}
box.once('init', function()
box.schema.space.create('s')
box.space.s:create_index('pk')
box.space.s:create_index('sk', {
unique = false,
parts = {
{2, 'number', path = 'a'},
{2, 'number', path = 'b'},
}
})
end)
box.space.s:truncate()
box.space.s:insert{1, {a = 1, b = 1}}
box.space.s:insert{2, {a = 1, b = 2}}
print('before delete')
print('---')
box.space.s:pairs():each(function(tuple)
print(json.encode(tuple))
end)
print('...')
local key_def = key_def_lib.new(box.space.s.index.pk.parts)
for _, tuple in box.space.s.index.sk:pairs({1}) do
local key = key_def:extract_key(tuple)
box.space.s.index.pk:delete(key)
end
print('after delete')
print('---')
box.space.s:pairs():each(function(tuple)
print(json.encode(tuple))
end)
print('...')
os.exit()
(source of the code)
Starting from Tarantool 2.1, you can use SQL syntax for that ('delete from ... where ...').
However, be aware that Tarantool will try to perfrom this in a transaction, so if you're trying to delete too many tuples, it will lock transaction thread for some time.
I have a list of strings, each one contains text with date like this:
"foo_6.7.2016"
"foo_5.10.2016"
"foo_6.30.2016"
"foo_6.23.2016"
"foo_6.2.2016"
"foo_5.22.2016"
I need to sort them by Date and get this:
"foo_6.30.2016"
"foo_6.23.2016"
"foo_6.7.2016"
"foo_6.2.2016"
"foo_5.22.2016"
"foo_5.10.2016"
An alternative might be:
def foos = [
"foo_6.7.2016",
"foo_5.10.2016",
"foo_6.30.2016",
"foo_6.23.2016",
"foo_6.2.2016",
"foo_5.22.2016"
]
def sorted = foos.sort(false) { Date.parse('M.d.yyyy', it - 'foo_') }.reverse()
For a quick answer that needs substantial cleanup:
def dates = [
"foo_6.7.2016"
"foo_5.10.2016"
"foo_6.30.2016"
"foo_6.23.2016"
"foo_6.2.2016"
"foo_5.22.2016"
]
def prefix = "foo_"
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("M.d.yyyy")
def sorted_dates = dates.collect{ sdf.parse(
it, new java.text.ParsePosition(prefix.length()) ) }.sort().reverse()
def newDates = sorted_dates.collect{ "${prefix} + ${sdf.format(it)}"}
println newDates
I need to parse a field from a CSV column which is a string:
TXDAT - SnpRespData_SC or SnpRespData_SC_PD (7)
I need to extract:
type_0 = SnpRespData
resp_0 = SC
pd_0 = 0
type_1 = SnpRespData
resp_1 = SC
pd_1 = 1
from this string. I want to pass the whole string to a function and be able to return these six values.
The string could be any of the following:
a) TXDAT - SnpRespData_SC_PD
b) TXRSP - SnpResp_SC
c) TXDAT - SnpRespData_SC or SnpRespData_SC_PD (7)
d) TXRSP - SnpResp_UC or TXDAT - SnpRespData_UC_PD (7)
So I created a function which receives this string and returns the following:
def map_rxsnp_transaction(rxsnp_transaction)
tx_dat = []
tx_rsp = []
case rxsnp_transaction
when (/SnpRespData.*SnpRespData/)
tx_dat = rxsnp_transaction.split(/or/)
(tx_dat_0, dat_0_resp, dat_0_pd) = tx_dat[0].split(/_/)
(tx_dat_1, dat_1_resp, dat_1_pd) = tx_dat[1].split(/_/)
return [tx_dat_0, dat_0_resp, dat_0_pd, tx_dat_1, dat_1_resp, dat_1_pd]
when (/SnpResp.*SnpRespData/)
(tx_rsp, tx_dat) = rxsnp_transaction.split(/or/)
(tx_rsp, rsp_resp, rsp_pd) = tx_rsp.split(/_/)
(tx_dat, dat_resp, dat_pd) = tx_dat.split(/_/)
return [tx_rsp, rsp_resp, rsp_pd, tx_dat, dat_resp, dat_pd]
when (/SnpRespData_{1}/)
return rxsnp_transaction.split(//)
when (/SnpResp{1}/)
return rxsnp_transaction.split(/_/)
end
end
Function call:
(tx_rsp[0],tx_rsp[1],tx_rsp[2],tx_rsp[3],tx_rsp[4],tx_rsp[5]) = map_rxsnp_transaction table_col[5]
Just wondering if I can optimize this code better...don't like the way it
I assume that you are looking for a specific string, namely, "SnpRespData". If so, you could do this:
str = "TXDAT - SnpRespData_SC or SnpRespData_SC_PD (7)"
f, l = str.scan(/SnpRespData\w+/).sort
#=> ["SnpRespData_SC", "SnpRespData_SC_PD"]
type_0, resp_0, pd_0 = f.split('_') << 0
#=> ["SnpRespData", "SC", 0]
type_1, resp_1, pd_1 = f.split('_').first(2) << 1
#=> ["SnpRespData", "SC", 1]
type_0 #=> "SnpRespData"
resp_0 #=> "SC"
pd_0 #=> 0
type_1 #=> "SnpRespData"
resp_1 #=> "SC"
pd_1 #=> 1