Pergunta

I have a range as follows:

my_range =  [1297134..1328348, 1381732..1382716, 1406478..1408262, 1425452..1427966, 1607341..1609354, 1616388..1616625, 1844576..1846076, 1847450..1847672]

I like to loop through all these ranges and find the difference between the last range and the next first range, so for example:

1381732 - 1328348
1406478 - 1382716
etc..

I know there is the first and last methods but I have no idea how to state the the last range and the next first range.

Would appreciate some help.

Foi útil?

Solução

You can use Enumerable#each_cons to iterate consecutive elements:

my_range =  [1297134..1328348, 1381732..1382716, 1406478..1408262, 1425452..1427966, 1607341..1609354, 1616388..1616625, 1844576..1846076, 1847450..1847672]
my_range.each_cons(2).map { |r1, r2| r2.first - r1.last }
#=> [53384, 23762, 17190, 179375, 7034, 227951, 1374]

Outras dicas

A third way, using Array#zip:

my_range = [
  1297134..1328348, 1381732..1382716, 1406478..1408262, 1425452..1427966,
  1607341..1609354, 1616388..1616625, 1844576..1846076, 1847450..1847672]

my_range[0..-2].zip(my_range.drop(1)).map { |r1,r2| r2.first-r1.last }
  #=> [53384, 23762, 17190, 179375, 7034, 227951, 1374]

If my_range is not sorted, step #1 is my_range.sort_by(&:first).

Edit:

On reflection, I'm not too happy with this. It's too close to @Stefan's answer and not as good, so I'll suggest something else that's quite simple:

enum = my_range.to_enum
a = []
loop do
  r1 = enum.next
  r2 = enum.peek
  a << r2.first-r1.last
end
a
  #=> [53384, 23762, 17190, 179375, 7034, 227951, 1374] 

Here Enumerator#peek raises a StopIteration exception if the enumerator is at its last element. Kernel#loop handles the exception by breaking out of the loop.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top