From: Raf Coremans Date: 2007-09-28T05:33:10+09:00 Subject: Re: Detecting number ranges ------=_Part_2741_32364832.1190925189435 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit Content-Disposition: inline 2007/9/26, Jay Levitt : > > I had to write a script this evening to take an unsorted input file of the > form: > > database 1 is on server 3 > database 8 is on server 7 > ... > > and output it in the form: > > server 3 handles database 1 through 7 > server 7 handles database 8 through 11 > > My brain was in procedural mode, and I wrote the following ugliness: > > --- > > def output_range(start_db, end_db, server_n) > puts "server #{server_n} handles database #{start_db} through > #{end_db}" > end > > open("db_list.txt").readlines.each do |line| > m = line.match(/^database (.*) is on server (.*)/) > db_n = m[1].to_i > server_n = m[2].to_i > > db_servers[db_n] = server_n > end > > range_start = 1 > > db_servers.each_index do |i| > next if i == 1 > if db_servers[i] != db_servers[i - 1] > output_range(range_start, i - 1, db_servers[i - 1]) > range_start = i > end > end > > last_db = db_servers.size - 1 > output_range(range_start, last_db, db_servers[last_db]) > --- > > which in fact is not only horrid to look at, but has a bug (it doesn't > like > it if the input skips over a database number, i.e. db 233 and 235 are > present but 234 is missing). > > I feel like there's a much nicer way to express this in Ruby, but can't > think of what it might be... > > > -- > Jay Levitt | > Boston, MA | My character doesn't like it when they > Faster: jay at jay dot fm | cry or shout or hit. > http://www.jay.fm | - Kristoffer > > Or use Set#divide: require 'set' ss = Set[*DATA.readlines.map{ |l| l.scan( /\d+/).map{ |s| s.to_i}.reverse}] ss = ss.divide{ |i, j| i[0] == j[0] && (i[1] - j[1]).abs <= 1} ss = ss.inject( {}){ |h, s| sa = s.to_a.sort; (h[sa.first[0]] ||= []) << (1 == sa.size ? sa.first[1] : sa.first[1]..sa.last[1]); h} ss.keys.sort.each{ |k| puts "Server #{k} handles db #{ss[k].sort_by{ |d| d.is_a?( Range) ? d.begin : d}.join( ', ')}"} __END__ database 8 is on server 7 database 10 is on server 7 database 9 is on server 7 database 5 is on server 9 database 1 is on server 3 database 2 is on server 3 database 133 is on server 3 database 4 is on server 144 => Server 3 handles db 1..2, 133 Server 7 handles db 8..10 Server 9 handles db 5 Server 144 handles db 4 Regards, R. ------=_Part_2741_32364832.1190925189435--