Jak policzyć identyczne elementy łańcuchowe w tablicy Ruby
Mam następujące Array = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
Jak stworzyć liczbę dla każdego identycznego elementu ?
Where:
"Jason" = 2, "Judah" = 3, "Allison" = 1, "Teresa" = 1, "Michelle" = 1?
Lub tworzy hash Gdzie:
Gdzie: hash = { "Jason" => 2, "Judah" => 3, "Allison" => 1, "Teresa" => 1, "Michelle" => 1 }
13 answers
names = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
counts = Hash.new(0)
names.each { |name| counts[name] += 1 }
# => {"Jason" => 2, "Teresa" => 1, ....
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-26 16:44:40
names.inject(Hash.new(0)) { |total, e| total[e] += 1 ;total}
Daje
{"Jason"=>2, "Teresa"=>1, "Judah"=>3, "Michelle"=>1, "Allison"=>1}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-26 16:55:13
Teraz używając Ruby 2.2.0 możesz wykorzystać itself
Metoda .
names = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
counts = {}
names.group_by(&:itself).each { |k,v| counts[k] = v.length }
# counts > {"Jason"=>2, "Teresa"=>1, "Judah"=>3, "Michelle"=>1, "Allison"=>1}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-14 18:18:02
Istnieje struktura danych, która robi to: MultiSet
.
Niestety, nie ma MultiSet
implementacji w bibliotece rdzeniowej Rubiego lub bibliotece standardowej, ale istnieje kilka implementacji pływających po Internecie.
Jest to świetny przykład na to, jak wybór struktury danych może uprościć algorytm. W rzeczywistości w tym konkretnym przykładzie algorytm nawet całkowicie odchodzi. To dosłownie:
Multiset.new(*names)
I to wszystko. Przykład, za pomocą https://GitHub.Com/Josh/Multimap/:
require 'multiset'
names = %w[Jason Jason Teresa Judah Michelle Judah Judah Allison]
histogram = Multiset.new(*names)
# => #<Multiset: {"Jason", "Jason", "Teresa", "Judah", "Judah", "Judah", "Michelle", "Allison"}>
histogram.multiplicity('Judah')
# => 3
Przykład, używając http://maraigue.hhiro.net/multiset/index-en.php : {]}
require 'multiset'
names = %w[Jason Jason Teresa Judah Michelle Judah Judah Allison]
histogram = Multiset[*names]
# => #<Multiset:#2 'Jason', #1 'Teresa', #3 'Judah', #1 'Michelle', #1 'Allison'>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-26 17:51:36
Poniższy kod nie był możliwy w standardowym ruby, kiedy to pytanie zostało zadane po raz pierwszy (luty 2011), ponieważ używa:
-
Object#itself
, który został dodany do Ruby v2.2.0 (Wydany w grudniu 2014). -
Hash#transform_values
, który został dodany do Ruby v2.4.0 (Wydany w grudniu 2016).
Te nowoczesne dodatki do Rubiego umożliwiają następującą implementację:
names = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
names.group_by(&:itself).transform_values(&:count)
#=> {"Jason"=>2, "Teresa"=>1, "Judah"=>3, "Michelle"=>1, "Allison"=>1}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-01 22:31:28
Enumberable#each_with_object
uchroni Cię przed zwrotem ostatniego hasha.
names.each_with_object(Hash.new(0)) { |name, hash| hash[name] += 1 }
Zwraca:
=> {"Jason"=>2, "Teresa"=>1, "Judah"=>3, "Michelle"=>1, "Allison"=>1}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-24 14:03:29
To działa.
arr = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
result = {}
arr.uniq.each{|element| result[element] = arr.count(element)}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-27 06:29:05
Poniżej znajduje się nieco bardziej funkcjonalny styl programowania:
array_with_lower_case_a = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
hash_grouped_by_name = array_with_lower_case_a.group_by {|name| name}
hash_grouped_by_name.map{|name, names| [name, names.length]}
=> [["Jason", 2], ["Teresa", 1], ["Judah", 3], ["Michelle", 1], ["Allison", 1]]
Jedną z zalet group_by
jest to, że można go używać do grupowania równoważnych, ale nie dokładnie identycznych przedmiotów:
another_array_with_lower_case_a = ["Jason", "jason", "Teresa", "Judah", "Michelle", "Judah Ben-Hur", "JUDAH", "Allison"]
hash_grouped_by_first_name = another_array_with_lower_case_a.group_by {|name| name.split(" ").first.capitalize}
hash_grouped_by_first_name.map{|first_name, names| [first_name, names.length]}
=> [["Jason", 2], ["Teresa", 1], ["Judah", 3], ["Michelle", 1], ["Allison", 1]]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-27 22:22:44
a = [1, 2, 3, 2, 5, 6, 7, 5, 5]
a.each_with_object(Hash.new(0)) { |o, h| h[o] += 1 }
# => {1=>1, 2=>2, 3=>1, 5=>3, 6=>1, 7=>1}
Kredyt Frank Wambutt
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-14 12:02:28
names = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
Hash[names.group_by{|i| i }.map{|k,v| [k,v.size]}]
# => {"Jason"=>2, "Teresa"=>1, "Judah"=>3, "Michelle"=>1, "Allison"=>1}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-18 20:28:18
To jest bardziej komentarz niż odpowiedź, ale komentarz nie zrobiłby tego sprawiedliwie. Jeśli wykonasz Array = foo
, zawieszasz co najmniej jedną implementację IRB:
C:\Documents and Settings\a.grimm>irb
irb(main):001:0> Array = nil
(irb):1: warning: already initialized constant Array
=> nil
C:/Ruby19/lib/ruby/site_ruby/1.9.1/rbreadline.rb:3177:in `rl_redisplay': undefined method `new' for nil:NilClass (NoMethodError)
from C:/Ruby19/lib/ruby/site_ruby/1.9.1/rbreadline.rb:3873:in `readline_internal_setup'
from C:/Ruby19/lib/ruby/site_ruby/1.9.1/rbreadline.rb:4704:in `readline_internal'
from C:/Ruby19/lib/ruby/site_ruby/1.9.1/rbreadline.rb:4727:in `readline'
from C:/Ruby19/lib/ruby/site_ruby/1.9.1/readline.rb:40:in `readline'
from C:/Ruby19/lib/ruby/1.9.1/irb/input-method.rb:115:in `gets'
from C:/Ruby19/lib/ruby/1.9.1/irb.rb:139:in `block (2 levels) in eval_input'
from C:/Ruby19/lib/ruby/1.9.1/irb.rb:271:in `signal_status'
from C:/Ruby19/lib/ruby/1.9.1/irb.rb:138:in `block in eval_input'
from C:/Ruby19/lib/ruby/1.9.1/irb/ruby-lex.rb:189:in `call'
from C:/Ruby19/lib/ruby/1.9.1/irb/ruby-lex.rb:189:in `buf_input'
from C:/Ruby19/lib/ruby/1.9.1/irb/ruby-lex.rb:103:in `getc'
from C:/Ruby19/lib/ruby/1.9.1/irb/slex.rb:205:in `match_io'
from C:/Ruby19/lib/ruby/1.9.1/irb/slex.rb:75:in `match'
from C:/Ruby19/lib/ruby/1.9.1/irb/ruby-lex.rb:287:in `token'
from C:/Ruby19/lib/ruby/1.9.1/irb/ruby-lex.rb:263:in `lex'
from C:/Ruby19/lib/ruby/1.9.1/irb/ruby-lex.rb:234:in `block (2 levels) in each_top_level_statement'
from C:/Ruby19/lib/ruby/1.9.1/irb/ruby-lex.rb:230:in `loop'
from C:/Ruby19/lib/ruby/1.9.1/irb/ruby-lex.rb:230:in `block in each_top_level_statement'
from C:/Ruby19/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `catch'
from C:/Ruby19/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `each_top_level_statement'
from C:/Ruby19/lib/ruby/1.9.1/irb.rb:153:in `eval_input'
from C:/Ruby19/lib/ruby/1.9.1/irb.rb:70:in `block in start'
from C:/Ruby19/lib/ruby/1.9.1/irb.rb:69:in `catch'
from C:/Ruby19/lib/ruby/1.9.1/irb.rb:69:in `start'
from C:/Ruby19/bin/irb:12:in `<main>'
C:\Documents and Settings\a.grimm>
To dlatego, że Array
jest klasą.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-27 22:09:01
Wiele świetnych implementacji tutaj.
Ale jako początkujący uznałbym to za najłatwiejsze do odczytania i wdrożenia
names = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
name_frequency_hash = {}
names.each do |name|
count = names.count(name)
name_frequency_hash[name] = count
end
#=> {"Jason"=>2, "Teresa"=>1, "Judah"=>3, "Michelle"=>1, "Allison"=>1}
Kroki, które podjęliśmy:
- stworzyliśmy hash
- zapętlamy tablicę
names
- policzyliśmy ile razy każda nazwa pojawiła się w tablicy
names
- stworzyliśmy klucz używając
name
i wartość używająccount
Może być nieco bardziej gadatliwy (a wydajność będzie robić niektóre niepotrzebne prace z nadpisującymi kluczami), ale moim zdaniem łatwiejsze do odczytania i zrozumienia dla tego, co chcesz osiągnąć
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-21 15:51:40
arr = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
arr.uniq.inject({}) {|a, e| a.merge({e => arr.count(e)})}
Czas upłynął 0,028 milisekundy
Co ciekawe, implementacja stupidgeeka:
Czas upłynął 0.041 milisekund
I zwycięska odpowiedź:
Czas upłynął 0.011 milisekund
:)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-05 22:24:38