Integers_ranges
I need to convert a String representation of sequences and ranges into something I can handle when building sql-strings.
str = '1,4-7,9,13..15,18-19,25'
def seq(s)
s.strip.tr(' ', '').split(',').map {
case it
when /^(\d+)$/ then $1.to_i
when /^(\d+)(?:\-|\.\.)(\d+)$/ then [*$1.to_i..$2.to_i]
else abort('ArgumentError (%s)' % it)
end
}.flatten.uniq.sort
end
p seq(str)
# => [1, 4, 5, 6, 7, 9, 13, 14, 15, 18, 19, 25]
Find any ranges in the sequence
def find_ranges(ar)
ar.chunk_while { |a,b| a+1 == b }.map {
it.size > 2 ? Range.new(it.first, it.last) : it[0]
}
end
seq = [1,4,5,6,7,9,13,14,15,18,19,25]
p find_ranges(ar)
# => [1, 4..7, 9, 13..15, 18, 25]
Need the sequences separated
seq = [1, 4..7, 9, 13..15, 18, 25]
p seq(str).partition { Range === it }
# ranges sequence
# => [[4..7, 13..15], [1, 9, 18, 25]]
Doing it like this.. there can be no intersections.. so no need to check for that.
First bug Link to heading
Number 19 is missing. Why?
Because: when a chunk comes with size == 2, I chose NOT to build a Range and just return it[0].
chunk [18, 19][0]
is 18
Solution?: replace it[0]
with it
and use flatten
on the result.
First test Link to heading
require 'mw_argv_xtras.rb'
require 'mw_sql_xtras.rb'
ids = [
'1,8,14, 13..19,9,8,1,2-8',
'5-15,12..21,4,5,22,26',
'2,3,4,5,6,7,8,10,5..11, 14,15',
'1-9,2-11,4-12,16,1-3,16..17,20',
'1,3,5,7,9',
'1-5, 7-12, 18-22'
].map {
ids = SeqRange::seq it
p it
puts SqlSeqRange::where ids
puts '-'*80
}
=begin OUTPUT
"1,8,14, 13..19,9,8,1,2-8"
id BETWEEN(1, 9) OR id BETWEEN(13, 19)
--------------------------------------------------------------------------------
"5-15,12..21,4,5,22,26"
id BETWEEN(4, 22) OR id IN (26)
--------------------------------------------------------------------------------
"2,3,4,5,6,7,8,10,5..11, 14,15"
id BETWEEN(2, 11) OR id IN (14, 15)
--------------------------------------------------------------------------------
"1-9,2-11,4-12,16,1-3,16..17,20"
id BETWEEN(1, 12) OR id IN (16, 17, 20)
--------------------------------------------------------------------------------
"1,3,5,7,9"
id IN (1, 3, 5, 7, 9)
--------------------------------------------------------------------------------
"1-5, 7-12, 18-22"
id BETWEEN(1, 5) OR id BETWEEN(7, 12) OR id BETWEEN(18, 22)
--------------------------------------------------------------------------------
=end