2011-01-11 16 views
13

względu posortowanej tablicy n liczb całkowitych, tak jak poniżej:różnice między elementami macierzy

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

potrzebne do obliczania różnicy między każdym elementem i następnego elementu tablicy. Korzystając z przykładu powyżej, chciałbym skończyć z:

[2, 1, 3, 5] 

Początek tablica może mieć 0, 1 lub wiele elementów w nim, a numery będę obsługa będzie znacznie większe (będę używał epochowe znaczniki czasu). Próbowałem następujące:

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]} 

Ale moje rozwiązanie powyżej jest zarówno nieoptymalne, a nie idealne. Czy ktoś może mi pomóc?

Odpowiedz

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: Zastąpiony inject z map.

+0

Jest to niezwykle zwięzły. Dzięki za wspaniałą odpowiedź. –

+4

Nice! Nie wiedziałem wcześniej o 'each_cons'. To jest nieco krótsza wersja tego samego: 'ary.each_cons (2) .map {| a, b | b-a} '. – Heikki

+0

Na marginesie: ważne jest nadanie nazwy abstrakcjom: [(a, b), (b, c), (c, d), ...] nazywane są "kombinacjami parami". I rzeczywiście enumerable.each_cons (2) .map jest najlepszym sposobem na zrobienie tego w Ruby (dzięki modułom wyliczającym wszystkie metody _xyz mogą być teraz używane "funkcjonalnie") – tokland

1

Alternatywą:

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

Nie działa w Ruby 1.8 gdzie map wymaga bloku zamiast powrotu moduł wyliczający.

7

podobne, ale bardziej zwięzły:

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

Jeszcze bardziej zwięzły jeśli zastąpisz 'collect' z' map':) Zauważ, że 'every_cons' nie jest dostępne w wersji 1.8.6, ale jest dostępne w wersji 1.8.7. – Phrogz

+0

Masz oczywiście rację, "map" jest lepsze niż "wstrzyknąć" tutaj. –