tags:

views:

64

answers:

2

Hi!

I've got an array of uniq numbers. Like this: [1,2,3,4,7,8,10,12]. It can be unsorted. What I need is to get intevals for this array:

intervals_for [1,2,3,4,7,8,10,12]
#=> "1-4, 7-8, 10,12"

I've got my own solution:

def intervals_for(array)
  array.sort!
  new_array = []
  array.each do |a|
    if new_array.last and a == new_array.last.last+1
      new_array.last << a
    else
      new_array << [a]    
    end
  end
  new_array.map{|a| a.size > 1 ? "#{a.first}-#{a.last}" : a.first}.join(", ")
end

But I think somewhere here is more clean solution

+2  A: 

here's mine, using ver 1.9.1

def torange(a)
  r=[];s=a[0]
  a.uniq.sort!.each_cons(2) do |a|
      r<<[s,a[0]] and s=a[1] if a[1]-a[0]!=1
  end
  left=a.index(s)
  r<<[a[left..-1][0],a[left..-1][-1]]
end

torange([1,2,3,4,7,8,10,12]).each do |x|
  puts x[0]==x[1] ? "#{x[0]}" : "#{x[0]}-#{x[1]}"
end

output

$ ruby test.rb
1-4
7-8
10
12
ghostdog74
Output is not so humane as I need. We need one more step to get this here: `"1-4, 7-8, 10, 12"`
fl00r
Thanx for `each_cons` method :) that's new for me
fl00r
well, the output is up to you to format it according to your wish. see my edit.
ghostdog74
cool, thank you
fl00r
@fl00r : torange([1,2,3,4,7,8,10,12]).map{|x| x[0] == x[1] ? x[0] : x.join('-') }.join(', ')
Mike Woodhouse
A: 

This one is recursive, feels like it could be better though...

arr =  [1,2,3,4,7,8,10,12]

def intervals(arr)
  return arr if arr.size == 0 || arr.size == 1

  int = [arr.shift]
  while int.last + 1 == arr.first
    int << arr.shift
  end

  ( int.size == 1 ? int : ["#{int.first}-#{int.last}"] ) + intervals(arr)
end

p intervals(arr)
Ben Marini