2011-01-11 3 views
13

Учитывая отсортированный массив из п целых чисел, как следующее:Вычислить различия между элементами массива

ary = [3, 5, 6, 9, 14] 

мне нужно вычислить разность между каждым элементом и следующим элементом в массиве. Используя пример выше, я бы в конечном итоге с:

[2, 1, 3, 5] 

Начинающему массив может иметь 0, 1 или несколько элементов в нем, а числа я буду обращение будет гораздо больше (я буду использовать временные метки эпохи). Я пробовал следующее:

times = @messages.map{|m| m.created_at.to_i} 
left = times[1..times.length-1] 
right = times[0..times.length-2] 
differences = left.zip(right).map { |x| x[0]-x[1]} 

Но мое решение выше и не является оптимальным, а не идеальным. Может ли кто-нибудь дать мне руку?

ответ

38
>> ary = [3, 5, 6, 9, 14] #=> [3, 5, 6, 9, 14] 
>> ary.each_cons(2).map { |a,b| b-a } #=> [2, 1, 3, 5] 

Edit: Заменено inject с map.

+0

Это удивительно кратким. Спасибо за замечательный ответ. –

+4

Ницца! Раньше я не знал о 'each_cons'. Это немного более короткая версия того же самого: 'ary.each_cons (2) .map {| a, b | б-а} '. – Heikki

+0

В качестве побочного примечания: важно дать имя абстракциям: [(a, b), (b, c), (c, d), ...] называются «попарными комбинациями». И действительно, enumerable.each_cons (2) .map - лучший способ сделать это в Ruby (благодаря счетчикам все методы every_xyz теперь могут быть использованы «функционально») – tokland

1

Альтернатива:

a.map.with_index{ |v,i| (a[i+1] || 0) - v }[0..-2] 

Не работает в Ruby 1.8, где map требует блок вместо возвращения счетчику.

7

Аналогичные, но более кратким:

[3, 5, 6, 9, 14].each_cons(2).collect { |a,b| b-a } 
+2

Еще более кратким, если вы замените 'collect' на' map':) Обратите внимание, что 'each_cons' недоступен в 1.8.6, но доступен в 1.8.7. – Phrogz

+0

Вы правы, конечно, 'map' лучше, чем' inject'. –

Смежные вопросы