Ruby 배열에서 동일한 문자열 요소를 계산하는 방법
나는 다음이있다 Array = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
각 동일한 요소에 대한 개수를 어떻게 생성 합니까?
Where:
"Jason" = 2, "Judah" = 3, "Allison" = 1, "Teresa" = 1, "Michelle" = 1?
또는 해시를 생성합니다 .
위치 : hash = { "Jason"=> 2, "Judah"=> 3, "Allison"=> 1, "Teresa"=> 1, "Michelle"=> 1}
names = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
counts = Hash.new(0)
names.each { |name| counts[name] += 1 }
# => {"Jason" => 2, "Teresa" => 1, ....
names.inject(Hash.new(0)) { |total, e| total[e] += 1 ;total}
당신에게 준다
{"Jason"=>2, "Teresa"=>1, "Judah"=>3, "Michelle"=>1, "Allison"=>1}
Ruby v2.4 이상 (현재)
이 질문을 처음으로 받았을 때 (2011 년 2 월) 표준 루비에서는 다음 코드를 사용할 수 없었습니다.
Object#itself
, Ruby v2.2.0 (2014 년 12 월 출시)에 추가되었습니다.Hash#transform_values
, 이는 Ruby v2.4.0 (2016 년 12 월 릴리스)에 추가되었습니다.
Ruby에 대한 이러한 최신 추가 기능을 통해 다음 구현이 가능합니다.
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}
Ruby v2.2 이상 (지원 중단됨)
위에서 언급 한 Hash#transform_values
방법에 액세스하지 않고 이전 루비 버전을 사용하는 경우 대신 Array#to_h
Ruby v2.1.0 (2013 년 12 월 릴리스)에 추가 된을 사용할 수 있습니다 .
names.group_by(&:itself).map { |k,v| [k, v.length] }.to_h
#=> {"Jason"=>2, "Teresa"=>1, "Judah"=>3, "Michelle"=>1, "Allison"=>1}
이전 루비 버전 ( <= 2.1
)의 경우이 문제를 해결할 수있는 여러 가지 방법이 있지만 (내 의견으로는) 명확한 "최상의"방법은 없습니다. 이 게시물에 대한 다른 답변을 참조하십시오.
(2019 년 2 월) 수정 :
Ruby v2.7 이상 (아직 출시되지 않음)
이 주석을 미래의 자리 표시 자로 간주하십시오. 루비 2.7.0
가 출시 되면 (2019 년 12 월 예정) 이 게시물을 업데이트 하여 메소드가 핵심 언어로되어 있는지 확인합니다.
최근 언어가 향상 되었습니다 . 모든 것이 계획대로 진행되면 Enumerable#tally
루비 v2.7.0에 추가 된 새로운 메서드 인을 보게 될 것입니다. 이 메서드는이 문제에 대해 특별히 새로운 구문을 추가합니다.
names = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
names.tally
#=> {"Jason"=>2, "Teresa"=>1, "Judah"=>3, "Michelle"=>1, "Allison"=>1}
이제 Ruby 2.2.0을 사용하여 itself
방법을 활용할 수 있습니다 .
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}
실제로이를 수행하는 데이터 구조가 MultiSet
있습니다..
불행히도 MultiSet
Ruby 코어 라이브러리 또는 표준 라이브러리 에는 구현 이 없지만 웹 주위에 떠 다니는 몇 가지 구현이 있습니다.
이것은 데이터 구조의 선택이 알고리즘을 단순화 할 수있는 방법을 보여주는 좋은 예입니다. 실제로이 특정 예에서는 알고리즘이 완전히 사라집니다. 말 그대로 다음과 같습니다.
Multiset.new(*names)
그리고 그게 다야. 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
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'>
Enumberable#each_with_object
최종 해시를 반환하지 않아도됩니다.
names.each_with_object(Hash.new(0)) { |name, hash| hash[name] += 1 }
보고:
=> {"Jason"=>2, "Teresa"=>1, "Judah"=>3, "Michelle"=>1, "Allison"=>1}
다음은 약간 더 기능적인 프로그래밍 스타일입니다.
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]]
의 한 가지 장점은 group_by
동일한 항목을 그룹화하는 데 사용할 수 있다는 것입니다.
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]]
작동합니다.
arr = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
result = {}
arr.uniq.each{|element| result[element] = arr.count(element)}
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}
Ruby 2.7 이상
Enumerable#tally
이 정확한 목적을 위해 Ruby 2.7이 도입 되었습니다. 여기에 좋은 요약이 있습니다 .
이 사용 사례에서 :
array.tally
# => { "Jason" => 2, "Judah" => 3, "Allison" => 1, "Teresa" => 1, "Michelle" => 1 }
출시되는 기능에 대한 문서는 여기에 있습니다 .
이것이 누군가를 돕기를 바랍니다!
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}
여기에 많은 훌륭한 구현이 있습니다.
하지만 초보자로서 저는 이것을 읽고 구현하기 가장 쉬운 것이라고 생각합니다.
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}
우리가 취한 조치 :
- we created the hash
- we looped over the
names
array - we counted how many times each name appeared in the
names
array - we created a key using the
name
and a value using thecount
It may be slightly more verbose (and performance wise you will be doing some unnecessary work with overriding keys), but in my opinion easier to read and understand for what you want to achieve
This is more a comment than an answer, but a comment wouldn't do it justice. If you do Array = foo
, you crash at least one implementation of 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>
That's because Array
is a class.
arr = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
arr.uniq.inject({}) {|a, e| a.merge({e => arr.count(e)})}
Time elapsed 0.028 milliseconds
interestingly, stupidgeek's implementation benchmarked:
Time elapsed 0.041 milliseconds
and the winning answer:
Time elapsed 0.011 milliseconds
:)
참고URL : https://stackoverflow.com/questions/5128200/how-to-count-identical-string-elements-in-a-ruby-array
'Development Tip' 카테고리의 다른 글
OSX에 MongoDB 설치 및 실행 (0) | 2020.11.02 |
---|---|
클래스 경로에서 파일 인스턴스로 파일을로드 / 참조하는 방법 (0) | 2020.11.02 |
.htaccess 리디렉션 http를 https로 (0) | 2020.11.02 |
FIQ와 IRQ 인터럽트 시스템의 차이점은 무엇입니까? (0) | 2020.11.02 |
angular.js 배열에서 요소 / 노드를 제거하는 방법 (0) | 2020.11.02 |