2012-05-25 15 views
6

Krótki kod w tytule jest w Haskell, robi rzeczy, jakElegancko realizacji 'mapy (+1) Lista' w Ruby

list.map {|x| x + 1} 

w Ruby.

Chociaż znam ten sposób, ale chcę wiedzieć, czy istnieją bardziej eleganckie sposoby na zaimplementowanie tego samego w rubinach, jak w Haskell.

Uwielbiam skrót to_proc w Ruby, jak tego formularza:

[1,2,3,4].map(&:to_s) 
[1,2,3,4].inject(&:+) 

Ale to tylko zaakceptować dokładnie dopasowując numer argumentu między Proc i metody.

Próbuję znaleźć sposób, który pozwala przekazać jeden lub więcej argumentów do Proc, i bez użycia niepotrzebnego tymczasowego bloku/zmiennej, jak to, co robi pierwsza demonstracja.

chcę zrobić tak:

[1,2,3,4].map(&:+(1)) 

Czy ruby ​​mają podobne sposoby, aby to zrobić?

+0

Widziałem klejnot na drugi dzień, ale nie pamiętam, jak to się nazywało inaczej niż "X". –

+0

@JoshLee Jeśli potrafisz przywołać klejnot, byłoby to bardzo cenne. –

+0

Aha, widziałem to w Wiadomościach Hackera. http://news.ycombinator.com/item?id=4003805 –

Odpowiedz

5

użytkowania, ampex klejnot, który pozwala używać metod X budować żadnemu PROC jedną jedną zmienną . Oto przykład z jego specyfikacją:

["a", "b", "c"].map(&X * 2).should == ["aa", "bb", "cc"] 
+0

Bardzo fajny klejnot! Myślę, że właśnie tego chcę! –

0

Jeśli chcesz po prostu dodać 1, można użyć next lub succ:

[1,2,3,4].map(&:next) 
[1,2,3,4].map(&:succ) 
7

Jeśli chcesz po prostu dodać jedną wtedy można użyć succ method:

>> [1,2,3,4].map(&:succ) 
=> [2, 3, 4, 5] 

Jeśli chciał aby dodać dwa, można użyć wartości lambda:

>> add_2 = ->(i) { i + 2 } 
>> [1,2,3,4].map(&add_2) 
=> [3, 4, 5, 6] 

Dla dowolnego użytkownika wartości, można użyć lambda, która buduje lambdy:

>> add_n = ->(n) { ->(i) { i + n } } 
>> [1,2,3,4].map(&add_n[3]) 
=> [4, 5, 6, 7] 

Można też zastosować metodę generowania lambda:

>> def add_n(n) ->(i) { i + n } end 
>> [1,2,3,4].map(&add_n(3)) 
=> [4, 5, 6, 7] 
+0

Nie dodawaj tylko jednego. Wygląda na to, że muszę zmienić przykładowe kody, aby nie dopuścić do nieporozumień ;-) –

+0

@ShouYa: Ale to dlatego wszystkie rzeczy 'add_n' również. –

3

Nie można zrobić to bezpośrednio z domyślnym map. Jednak całkiem łatwo jest zaimplementować wersję obsługującą tego typu funkcje. Jako przykład Ruby Facets zawiera właśnie taką metodę:

require 'facets/enumerable' 

[1, 2, 3, 4].map_send(:+, 10) 
=> [11, 12, 13, 14] 

Realizacja wygląda następująco:

def map_send(meth, *args, &block) 
    map { |e| e.send(meth, *args, &block) } 
end 
1

Ruby nie posiada wbudowane wsparcie dla tej funkcji, ale można tworzyć własne rozszerzenia lub użyć małego klejnotu „ampex”. Definiuje globalną zmienną X z rozszerzoną funkcjonalnością "to_proc".

To daje możliwość, aby to zrobić:

[1,2,3].map(&X.+(1)) 

Albo nawet, że:

"alpha\nbeta\ngamma\n".lines.map(&X.strip.upcase) 
2

W ten konkretny przypadek, można użyć następujący:

[1, 2, 3, 4].map(&1.method(:+)) 

Działa to jednak tylko dlatego, że + nie jest skojarzone ve. Na przykład nie zadziała dla -.

Powiązane problemy