Jak mogę użyć tego sposobu do zsumowania atrybutu z obiektu. Moja tablica [produkt1, produkt2] Chcę zsumować produkt1. cena + produkt2. cena. Czy jest to możliwe przy użyciu array.inject (: +)?
array.map(&:price).inject(0, :+)jest nieco bezpieczniejszy. Zapewnia to, że jeśli masz pustą listę, dostajesz 0 zamiast zera .
johnf
11
za pomocą array.map (...). inject (...) jest nieefektywny, powtórzysz wszystkie dane dwa razy. Spróbuj array.inject(0) { |sum, product| sum += product.price }
Choć odpowiednik array.inject(0, :+)terminu „ redukuj” wchodzi w bardziej popularne języki wraz ze wzrostem modeli programowania MapReduce .
wstrzykiwanie , zmniejszanie , składanie , gromadzenie i kompresja są synonimami jako klasa funkcji składania . Najważniejsza jest spójność w całej bazie kodu, ale ponieważ różne społeczności wolą jedno słowo od drugiego, warto jednak znać alternatywy.
Aby podkreślić znaczenie ograniczania mapy, oto wersja, która jest nieco bardziej wyrozumiała dla tego, co kończy się w tej tablicy.
Zgadzam się, reducemówi mi więcej o tym, co robi ta funkcja, ale injectbrzmi znacznie lepiej .
everett1992
1
Zgadzam się z ostatnim komentarzem, dałeś mi najlepszą odpowiedź.
Jerska
1
Jedyny komentarz chciałbym zrobić jest to, że reducei maptak funkcje wyższego rzędu poprzedzają MapReduce. Inspiracja działa w drugą stronę. W sensie MapReduce jest to nieco inna operacja niż zwykła redukcja funkcjonalna, mająca implikacje dla sposobu komunikowania się różnych maszyn.
acjay
Ken Iverson wprowadził operator / nazywany „operatorem redukcji” w języku programowania APL. Źródło: Iverson, Kenneth. 1962. Język programowania. Wiley. Inne źródło: „Notacja jako narzędzie myśli”, wykład ACM Turinga z 1979 r., Kenneth E. Iverson, dl.acm.org/ft_gateway.cfm?id=1283935&type=pdf
Fernando Pelliccioni
112
Alternatywnie (tylko dla porównania), jeśli masz zainstalowane Railsy (właściwie tylko ActiveSupport):
Nowsze wersje activesupport nie ładują domyślnie wszystkich rozszerzeń. Będziemy chcieli albo wymagają tylko moduł Suma: require 'active_support/core_ext/enumerable.rb'lub wymagają wszystkie aktywnego wsparcia: require 'active_support/all'. Więcej informacji na ten temat tutaj: Dokumenty API
dcashman
2
Nieważne, że activesupportjest masywny zależność do przeciągania do projektu, aby przejść od array.inject(:+)do array.sum.
meagar
1
Nitpick do skądinąd dobrego komentarza: powinien być require 'active_support/core_ext/enumerable'bez .rbprzyrostka, ponieważ jest to dodawane domyślnie.
Per Lundberg,
72
Dla Ruby> = 2.4.0 możesz używać sumz Enumerables.
[1,2,3,4].sum
Klasy podstawowe typu mokeypatch są niebezpieczne. Jeśli lubisz niebezpieczeństwo i używasz starszej wersji Ruby, możesz dodać #sumdo Arrayklasy:
classArraydef sum
inject(0){|sum, x| sum + x }endend
Chodzi mu o to, że nie musisz wykonywać Małpiej łatki dla Ruby> = 2.4, i że łatanie małp jest niebezpieczne, i że możesz teraz sumować wyliczenia natywnie, ale jest też sposób na cofnięcie funkcjonalności.
Peter H. Boling,
Odebrano, ponieważ twoja implementacja zwraca zero na pustych tablicach.
Eldritch Conundrum
45
Nowość w Ruby 2.4.0
Możesz użyć trafnie nazwanej metody Enumerable#sum. Ma wiele zalet, inject(:+)ale na końcu jest też kilka ważnych uwag.
Ta metoda nie jest równoważna z #inject(:+). Na przykład
%w(a b c).inject(:+)#=> "abc"%w(a b c).sum
#=> TypeError: String can't be coerced into Integer
Również,
(1..1000000000).sum
#=> 500000000500000000 (execution time: less than 1s)(1..1000000000).inject(:+)#=> 500000000500000000 (execution time: upwards of a minute)
Zobacz tę odpowiedź, aby uzyskać więcej informacji o tym, dlaczego sumtak jest.
Ze względu na różnorodność możesz to zrobić, jeśli tablica nie jest tablicą liczb, ale tablicą obiektów, które mają właściwości, które są liczbami (np. Ilość):
Jest to równoważne temu: array.map(&:amount).inject(0, :+). Zobacz inne odpowiedzi.
Richard Jones
4
W pewnym sensie tak. Jednak użycie mapwtedy injectwymaga dwukrotnego przejścia przez tablicę: raz, aby utworzyć nową tablicę, drugi, aby zsumować członków. Ta metoda jest nieco bardziej szczegółowa, ale także bardziej wydajna.
# http://madeofcode.com/posts/74-ruby-core-extension-array-sumclassArraydef sum(method =nil,&block)if block_given?
raise ArgumentError,"You cannot pass a block and a method!"if method
inject(0){|sum, i| sum +yield(i)}elsif method
inject(0){|sum, i| sum + i.send(method)}else
inject(0){|sum, i| sum + i }endendend
Spowoduje to utworzenie ciągu „123 + 321 + 12389”, a następnie użycie funkcji eval do wykonania sumy. Jest to wyłącznie do celów golfowych , nie należy używać go we właściwym kodzie.
[1] pry(main)>[1,2,3,4].sum
=>10[2] pry(main)>[].sum
=>0[3] pry(main)>[1,2,3,5,nil].sum
TypeError:nil can't be coerced into Integer
Metoda 2:
[24] pry(main)>[].inject(:+)=>nil[25] pry(main)>[].inject(0,:+)=>0[4] pry(main)>[1,2,3,4,5].inject(0,:+)=>15[5] pry(main)>[1,2,3,4,nil].inject(0,:+)TypeError:nil can't be coerced into Integer
from (pry):5:in `+'
Metoda 3:
[6] pry(main)>[1,2,3].reduce(:+)=>6[9] pry(main)>[].reduce(:+)=>nil[7] pry(main)>[1,2,nil].reduce(:+)TypeError:nil can't be coerced into Integer
from (pry):7:in `+'
Metoda 4:
Gdy tablica zawiera zero i puste wartości, domyślnie, jeśli użyjesz którejkolwiek z powyższych funkcji zmniejsz, podsumuj, wstrzyknij wszystko przez
TypeError: zero nie może być zmuszone do liczby całkowitej
Możesz to przezwyciężyć,
[16] pry(main)> sum =0=>0[17] pry(main)>[1,2,3,4,nil,''].each{|a| sum+= a.to_i }=>[1,2,3,4,nil,""][18] pry(main)> sum
=>10
Metoda 6: eval
Ocenia wyrażenie Ruby w ciągu.
[26] pry(main)> a =[1,3,4,5]=>[1,3,4,5][27] pry(main)> eval a.join '+'=>13[30] pry(main)> a =[1,3,4,5,nil]=>[1,3,4,5,nil][31] pry(main)> eval a.join '+'SyntaxError:(eval):1: syntax error, unexpected end-of-input
1+3+4+5+
array.sum
Odpowiedzi:
Spróbuj tego:
Zobacz wyliczalną dokumentację Ruby
(uwaga:
0
potrzebna jest skrzynka podstawowa, aby0
zamiast niej została zwrócona pusta tablicanil
)źródło
array.inject(:+)
jest bardziej wydajny.array.inject(:+)
wydaje się powodować problemy w wyjątkach Ruby 1.8.6 „LocalJumpError: nie podano żadnego bloku” może się pojawić.array.sum
może dać ci sumę wartości tablicy.reduce
, który jest aliaseminject
(jak warray.reduce( :+ )
).inject
zamiastreduce
.Lub wypróbuj sposób Ruby 1.9:
Uwaga:
0
skrzynka podstawowa jest potrzebna, w przeciwnym razienil
zostaną zwrócone w pustych tablicach:źródło
array.map(&:price).inject(0, :+)
jest nieco bezpieczniejszy. Zapewnia to, że jeśli masz pustą listę, dostajesz 0 zamiast zera .array.inject(0) { |sum, product| sum += product.price }
Choć odpowiednik
array.inject(0, :+)
terminu „ redukuj” wchodzi w bardziej popularne języki wraz ze wzrostem modeli programowania MapReduce .wstrzykiwanie , zmniejszanie , składanie , gromadzenie i kompresja są synonimami jako klasa funkcji składania . Najważniejsza jest spójność w całej bazie kodu, ale ponieważ różne społeczności wolą jedno słowo od drugiego, warto jednak znać alternatywy.
Aby podkreślić znaczenie ograniczania mapy, oto wersja, która jest nieco bardziej wyrozumiała dla tego, co kończy się w tej tablicy.
Kilka dodatkowych istotnych lektur:
źródło
reduce
mówi mi więcej o tym, co robi ta funkcja, aleinject
brzmi znacznie lepiej .reduce
imap
tak funkcje wyższego rzędu poprzedzają MapReduce. Inspiracja działa w drugą stronę. W sensie MapReduce jest to nieco inna operacja niż zwykła redukcja funkcjonalna, mająca implikacje dla sposobu komunikowania się różnych maszyn.Alternatywnie (tylko dla porównania), jeśli masz zainstalowane Railsy (właściwie tylko ActiveSupport):
źródło
require 'active_support/core_ext/enumerable.rb'
lub wymagają wszystkie aktywnego wsparcia:require 'active_support/all'
. Więcej informacji na ten temat tutaj: Dokumenty APIactivesupport
jest masywny zależność do przeciągania do projektu, aby przejść odarray.inject(:+)
doarray.sum
.require 'active_support/core_ext/enumerable'
bez.rb
przyrostka, ponieważ jest to dodawane domyślnie.Dla Ruby> = 2.4.0 możesz używać
sum
z Enumerables.Klasy podstawowe typu mokeypatch są niebezpieczne. Jeśli lubisz niebezpieczeństwo i używasz starszej wersji Ruby, możesz dodać
#sum
doArray
klasy:źródło
Nowość w Ruby 2.4.0
Możesz użyć trafnie nazwanej metody
Enumerable#sum
. Ma wiele zalet,inject(:+)
ale na końcu jest też kilka ważnych uwag.Przykłady
Zakresy
Tablice
Ważna uwaga
Ta metoda nie jest równoważna z
#inject(:+)
. Na przykładRównież,
Zobacz tę odpowiedź, aby uzyskać więcej informacji o tym, dlaczego
sum
tak jest.źródło
Ze względu na różnorodność możesz to zrobić, jeśli tablica nie jest tablicą liczb, ale tablicą obiektów, które mają właściwości, które są liczbami (np. Ilość):
źródło
array.map(&:amount).inject(0, :+)
. Zobacz inne odpowiedzi.map
wtedyinject
wymaga dwukrotnego przejścia przez tablicę: raz, aby utworzyć nową tablicę, drugi, aby zsumować członków. Ta metoda jest nieco bardziej szczegółowa, ale także bardziej wydajna.Ruby 2.4+ / Rails -
array.sum
tj[1, 2, 3].sum # => 6
Ruby przed 2.4 -
array.inject(:+)
lubarray.reduce(:+)
* Uwaga:
#sum
Metoda jest nowym dodatkiem do 2.4,enumerable
dzięki czemu będziesz mógł używaćarray.sum
czystego rubinu, nie tylko Railsów.źródło
Ruby 1.8.7 to:
źródło
Możesz po prostu użyć:
źródło
inject(:+)
ale to nie działainject :+
?Wystarczy
[1,2,3].inject('+')
źródło
Ruby 2.4.0 zostało wydane i ma metodę Enumerable # sum . Więc możesz to zrobić
Przykłady z dokumentów:
źródło
Pozwala również na
[1,2].sum{|x| x * 2 } == 6
:źródło
dla tablicy z zerowymi wartościami możemy wykonać kompaktowanie, a następnie wstrzyknąć sumę ex-
źródło
Działa również dla zakresów ... stąd
źródło
Jeśli czujesz się golfistą, możesz to zrobić
Spowoduje to utworzenie ciągu „123 + 321 + 12389”, a następnie użycie funkcji eval do wykonania sumy. Jest to wyłącznie do celów golfowych , nie należy używać go we właściwym kodzie.
źródło
Metoda 1:
Metoda 2:
Metoda 3:
Metoda 4: Gdy tablica zawiera zero i puste wartości, domyślnie, jeśli użyjesz którejkolwiek z powyższych funkcji zmniejsz, podsumuj, wstrzyknij wszystko przez
Możesz to przezwyciężyć,
Metoda 6: eval
Ocenia wyrażenie Ruby w ciągu.
źródło
3 sposoby na wykonanie sumy tablic
1)
array.inject(0){|sum,x| sum + x }
2)
array.inject('+')
3)
array.join('+')
źródło
Lub możesz wypróbować tę metodę:
źródło
To jest najkrótsza droga. Spróbuj.
array.inject :+
źródło
* To działało dobrze dla mnie jako nowego programisty. Możesz dostosować zakres liczb, zmieniając wartości w []
źródło
Możesz to również zrobić w prosty sposób
źródło
Możesz użyć .map i .sum, takich jak:
źródło
array.sum