রুবি অ্যারেতে কীভাবে অভিন্ন স্ট্রিং উপাদানগুলি গণনা করা যায়


91

আমি নিম্নলিখিত আছে Array = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]

আমি কীভাবে প্রতিটি অভিন্ন উপাদানটির জন্য একটি গণনা তৈরি করতে পারি ?

Where:
"Jason" = 2, "Judah" = 3, "Allison" = 1, "Teresa" = 1, "Michelle" = 1?

বা একটি হ্যাশ উত্পাদন যেখানে:

যেখানে: হ্যাশ = {"জেসন" => 2, "এহুদা" => 3, "অ্যালিসন" => 1, "তেরেসা" => 1, "মিশেল" => 1


4
রুবি ২.7 হিসাবে আপনি ব্যবহার করতে পারেন Enumerable#tally। আরও তথ্য এখানে ।
— এসআরাক

উত্তর:



127
names.inject(Hash.new(0)) { |total, e| total[e] += 1 ;total}

আপনি দেয়

{"Jason"=>2, "Teresa"=>1, "Judah"=>3, "Michelle"=>1, "Allison"=>1} 

4
+1 নির্বাচিত উত্তরের মতো, তবে আমি ইনজেকশন এবং কোনও "বাহ্যিক" ভেরিয়েবল ব্যবহার পছন্দ করি না।

18
আপনি যদি তার each_with_objectপরিবর্তে ব্যবহার করেন তবে ব্লকে inject( ;total) ফিরে আসতে হবে না ।
— এমফিলিজ

12
উত্তরসূরীদের জন্য, @ এমফিলিজ এর অর্থ:array.each_with_object(Hash.new(0)){|string, hash| hash[string] += 1}
— গন জিফ্রোনি

4
রুবি 2.7 থেকে, আপনি কেবল করতে পারেন: names.tally।
— হলজিয়ার উইলহেলমসেন

99

রুবি ভি 2.7 + (সর্বশেষ)

রুবি ভি 2.7.0 (ডিসেম্বর 2019 প্রকাশিত) হিসাবে, মূল ভাষার অন্তর্ভুক্ত রয়েছে Enumerable#tally- একটি নতুন পদ্ধতি , বিশেষত এই সমস্যার জন্য ডিজাইন করা:

names = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]

names.tally
#=> {"Jason"=>2, "Teresa"=>1, "Judah"=>3, "Michelle"=>1, "Allison"=>1}

রুবি ভি 2.4 + (বর্তমানে সমর্থিত তবে বয়স্ক)

এই প্রশ্নটি প্রথম জিজ্ঞাসা করা হলে (ফেব্রুয়ারী ২০১১) নীচের কোডটি স্ট্যান্ডার্ড রুবিতে সম্ভব ছিল না, যেমন এটি ব্যবহার করে:

  • Object#itselfযা রুবি ভি 2.2.0 এ যুক্ত হয়েছিল (ডিসেম্বর 2014 এ প্রকাশিত)।
  • Hash#transform_valuesযা রুবি ভি 2.4.0 এ যুক্ত হয়েছিল (ডিসেম্বর 2016 প্রকাশিত হয়েছে)।

রুবির এই আধুনিক সংযোজনগুলি নিম্নলিখিত বাস্তবায়ন সক্ষম করে:

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}

রুবি ভি ২.২ + (অবমানিত)

যদি উপরে বর্ণিত Hash#transform_valuesপদ্ধতিতে অ্যাক্সেস না করে কোনও পুরানো রুবি সংস্করণ ব্যবহার করা হয় তবে আপনি পরিবর্তে এটি ব্যবহার করতে পারেন Array#to_hযা রুবি ভি ২.১.০ (ডিসেম্বর ২০১৩ প্রকাশিত) এ যুক্ত হয়েছিল:

names.group_by(&:itself).map { |k,v| [k, v.length] }.to_h
#=> {"Jason"=>2, "Teresa"=>1, "Judah"=>3, "Michelle"=>1, "Allison"=>1}

এমনকি পুরানো রুবি সংস্করণগুলির জন্য ( <= 2.1), এটি সমাধানের বিভিন্ন উপায় রয়েছে তবে (আমার মতে) কোনও পরিষ্কার-কাট "সেরা" উপায় নেই। এই পোস্টে অন্যান্য উত্তর দেখুন।


আমি পোস্ট করতে চলেছিলাম: পি। / এর countপরিবর্তে ব্যবহারের মধ্যে কি কোনও পৃথক পৃথক রয়েছে ? sizelength
— বরফ

4
@ সাগরপাণ্ড্য না, কোনও পার্থক্য নেই। ভিন্ন Array#sizeএবং Array#length, Array#count করতে একটি ঐচ্ছিক আর্গুমেন্ট বা ব্লক নেওয়া; তবে যদি উভয়ের সাথে ব্যবহার হয় তবে এর প্রয়োগটি অভিন্ন। আরও সুনির্দিষ্টভাবে, তিনটি পদ্ধতিই ফণাটির LONG2NUM(RARRAY_LEN(ary))নীচে কল করে: গণনা / দৈর্ঘ্য
— টম লর্ড

4
এটি আইডিয়োম্যাটিক রুবির যেমন একটি দুর্দান্ত উদাহরণ। দুর্দান্ত উত্তর।
— slhck

4
অতিরিক্ত creditণ! গণনা অনুসারে বাছাই করুন.group_by(&:itself).transform_values(&:count).sort_by{|k, v| v}.reverse
— আব্রাম

4
@ আব্রাম আপনি পারবেন sort_by{ |k, v| -v}, reverseপ্রয়োজন নেই! ;-)
— সনি সান্টোস

26

এখন রুবি ২.২.০ ব্যবহার করে আপনি 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}

4
সম্মত হন, তবে আমি নামগুলিকে কিছুটা পছন্দ করি (যেমন: & নিজেই)। ম্যাপ {| কে, ভি | [কে, ভি.কাউন্ট] to। ট_এইচ যাতে আপনাকে কোনও হ্যাশ অবজেক্ট কখনও ঘোষণা করতে না হয়
— অ্যান্ডি ডে

8
@ অ্যান্ড্রুউকডে আরও এক ধাপ এগিয়ে, রুবি ভি 2.4 পদ্ধতিটি যুক্ত করেছে: Hash#transform_valuesযা আমাদের আপনার কোডটিকে আরও সহজ করার অনুমতি দেয়:names.group_by(&:itself).transform_values(&:count)
— টম লর্ড

এছাড়াও, এটি একটি খুব সূক্ষ্ম বিন্দু (যা সম্ভবত ভবিষ্যতের পাঠকদের কাছে প্রাসঙ্গিক নয়!) তবে নোট করুন যে আপনার Array#to_hকোডটিও ব্যবহার করে - যা রুবি ভি ২.১.০ এ যুক্ত হয়েছিল (ডিসেম্বর ২০১৩ প্রকাশিত হয়েছে - অর্থাত্ মূল প্রশ্নের প্রায় 3 বছর পরে জিজ্ঞাসা করা হয়েছিল!)
— টম লর্ড

17

সেখানে আসলে একটি ডাটা স্ট্রাকচার যা এই আছে আছে: MultiSet।

দুর্ভাগ্যক্রমে, MultiSetরুবি কোর লাইব্রেরি বা স্ট্যান্ডার্ড লাইব্রেরিতে কোনও প্রয়োগ নেই , তবে ওয়েবের চারপাশে বেশ কয়েকটি বাস্তবায়ন ভাসমান।

এটি কীভাবে ডেটা কাঠামোর পছন্দ একটি অ্যালগোরিদমকে সহজ করতে পারে তার একটি দুর্দান্ত উদাহরণ। আসলে, এই বিশেষ উদাহরণে, অ্যালগরিদম এমনকি পুরোপুরি চলে যায়। এটি আক্ষরিকভাবে ঠিক:

Multiset.new(*names)

এবং এটাই. উদাহরণস্বরূপ, https://GitHub.Com/ জোশ / মাল্টিম্যাপ / ব্যবহার করে :

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'>

মাল্টিসেট ধারণাটি কি গণিত, বা অন্য কোনও প্রোগ্রামিং ভাষা থেকে উদ্ভূত হয়েছে?
— অ্যান্ড্রু গ্রিম

4
@Andrew গ্রিম: উভয় তিনি শব্দ "multiset" (ডি Bruijn, 1970) এবং ধারণা (Dedekind 1888) গণিত মধ্যে সম্ভূত। Multisetকঠোর গাণিতিক নিয়ম দ্বারা পরিচালিত হয় এবং আদর্শ সেট অপারেশনগুলিকে সমর্থন করে (ইউনিয়ন, ছেদ, পরিপূরক, ...) এমন এক উপায়ে যা বেশিরভাগ অক্ষ, আইন এবং "সাধারণ" গাণিতিক সেট তত্ত্বের তত্ত্বগুলির সাথে সামঞ্জস্যপূর্ণ, যদিও কিছু গুরুত্বপূর্ণ আইন করে যখন আপনি তাদের বহুসীকরণে সাধারণ করার চেষ্টা করবেন তখন হোল্ড করবেন না । তবে বিষয়টি আমার বোঝার বাইরে। আমি এগুলিকে গাণিতিক ধারণা হিসাবে নয়, প্রোগ্রামিং ডেটা স্ট্রাকচার হিসাবে ব্যবহার করি।
— Jörg ডব্লু মিটাগ

এই দফায় কিছুটা প্রসারিত করার জন্য : "... এমন একটি উপায়ে যা বেশিরভাগ অক্ষের সাথে সামঞ্জস্যপূর্ণ ..." : "নরমাল" সেটগুলি সাধারণত "জেরেমো-ফ্রাঙ্কেল সেট থিয়োরি" নামক অ্যাকোরিওমের (অনুমান) একটি সেট দ্বারা আনুষ্ঠানিকভাবে সংজ্ঞায়িত হয় called "। যাইহোক, এই অক্ষরগুলির মধ্যে একটি: এক্সটেনসিলিটির অক্ষরূপে বলা হয় যে একটি সেট তার সদস্যদের দ্বারা যথাযথভাবে সংজ্ঞায়িত করা হয়েছে - যেমন {A, A, B} = {A, B}। এটি স্পষ্টতই মাল্টি-সেটগুলির খুব সংজ্ঞা লঙ্ঘন!
— টম লর্ড

... তবে খুব বেশি বিশদে না গিয়ে (যেহেতু এটি একটি সফটওয়্যার ফোরাম, অ্যাডভান্সড ম্যাথস নয়!), কেউ ক্রিস্প সেটস, পিয়ানো অ্যাকোয়ামস এবং অন্যান্য মাল্টিসেট-নির্দিষ্ট অক্ষরেখার জন্য অলিম্পিকের মাধ্যমে গাণিতিকভাবে মাল্টি-সেট সংজ্ঞায়িত করতে পারেন ine
— টম লর্ড

13

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}

সম্মত হোন, each_with_objectরূপটি আমার কাছে আরও পাঠযোগ্যinject
— লেভ লুকমস্কি

9

রুবি ২.7+

রুবি ২.7 Enumerable#tallyএই সঠিক উদ্দেশ্যে প্রবর্তন করছে । এখানে একটি ভাল সারসংক্ষেপ আছে ।

এই ব্যবহারের ক্ষেত্রে:

array.tally
# => { "Jason" => 2, "Judah" => 3, "Allison" => 1, "Teresa" => 1, "Michelle" => 1 }

প্রকাশিত হওয়া বৈশিষ্ট্যগুলির দস্তাবেজগুলি এখানে রয়েছে ।

আশা করি এটি কাউকে সাহায্য করবে!


চমত্কার খবর!
— tadman

6

এইটা কাজ করে.

arr = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]
result = {}
arr.uniq.each{|element| result[element] = arr.count(element)}

4
+1 ভিন্ন পদ্ধতির জন্য - যদিও এটির তাত্ত্বিক জটিলতা আরও খারাপ - O(n^2)(যা কিছু মূল্যবোধের জন্য বিবেচিত হবে n) এবং অতিরিক্ত কাজ করে (এটি "যিহূদা" 3x হিসাবে গণনা করতে হবে)! আমি এর eachপরিবর্তে map(মানচিত্রের ফলাফলটি বাতিল করা হচ্ছে)

তার জন্য ধন্যবাদ! আমি প্রত্যেকটিতে মানচিত্র পরিবর্তন করেছি A এছাড়াও, আমি অ্যারেটি চালিয়ে যাওয়ার আগে অকেইক করেছি। জটিলতার বিষয়টি এখন কি সমাধান হবে?
— শ্রেয়াস

6

নীচে একটি সামান্য আরও কার্যকরী প্রোগ্রামিং শৈলী:

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

আমি কি কার্যকরী প্রোগ্রামিং শুনেছি? +1 :-) এটি অবশ্যই সঠিক উপায়, যদিও এটি যুক্তিযুক্ত যে মেমরি-দক্ষ নয়। এটিও লক্ষ করুন যে দিকগুলির একটি পরিমিত # ফ্রিকোয়েন্সি রয়েছে।
— টোকল্যান্ড


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

2

এখানে প্রচুর দুর্দান্ত বাস্তবায়ন।

তবে একটি শিক্ষানবিস হিসাবে আমি এটি পড়ার এবং বাস্তবায়নের সবচেয়ে সহজ বিবেচনা করব

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}

আমরা যে পদক্ষেপ নিয়েছি:

  • আমরা হ্যাশ তৈরি করেছি
  • আমরা namesঅ্যারের উপরে লুপ করেছি
  • আমরা গণনা করেছি যে প্রতিটি নাম namesঅ্যারেতে উপস্থিত হয়েছিল কতবার
  • আমরা কী ব্যবহার করে nameএকটি এবং একটি মান ব্যবহার করে তৈরি করেছিcount

এটি সামান্য আরও ভারবজ হতে পারে (এবং পারফরম্যান্স অনুসারে আপনি ওভাররাইড কীগুলি দিয়ে কিছু অপ্রয়োজনীয় কাজ করছেন) তবে আপনি কী অর্জন করতে চান তার জন্য আমার মতে পড়া এবং বুঝতে সহজ


4
আমি দেখতে পাচ্ছি না যে এটি গ্রহণযোগ্য উত্তরের চেয়ে পড়া আরও সহজ এবং এটি স্পষ্টতই একটি খারাপ নকশা (প্রচুর অপ্রয়োজনীয় কাজ করে))
— টম লর্ড

@ টম লর্ড - আমি পারফরম্যান্সের সাথে আপনার সাথে একমত হয়েছি (এমনকি আমি আমার উত্তরে এটি উল্লেখ করেছি) - তবে একজন শিক্ষানবিস হিসাবে প্রকৃত কোড এবং প্রয়োজনীয় পদক্ষেপগুলি বোঝার চেষ্টা করে আমি খুঁজে পেয়েছি এটি আরও ভার্জোজ হতে সহায়তা করে এবং তারপরে কেউ উন্নতি করতে পারে রিফ্যাক্টর পারফরম্যান্স এবং
— কোডটিকে

4
আমি @ সামিবার্নবাউমের সাথে কিছুটা একমত এটি একমাত্র যা প্রায় কোনও বিশেষ রুবি জ্ঞানের মতো ব্যবহার করে না Hash.new(0)। সিউডোকোডের সবচেয়ে কাছের। এটি পাঠযোগ্যতার পক্ষে ভাল জিনিস হতে পারে তবে অপ্রয়োজনীয় কাজ করা পাঠকদের পক্ষে পাঠযোগ্যতার ক্ষতি করতে পারে যারা এটি লক্ষ্য করে কারণ আরও জটিল ক্ষেত্রে তারা কেন এমনটি হয়েছে তা জানার চেষ্টা করে পাগল হয়ে যাওয়ার ভেবে কিছুটা সময় ব্যয় করবেন।
— Adamantish

1

এটি একটি উত্তরের চেয়ে বেশি মন্তব্য, তবে একটি মন্তব্য এটি ন্যায়বিচার করে না। যদি আপনি তা করেন তবে আপনি Array = fooকমপক্ষে একটি আইআরবি প্রয়োগের ক্র্যাশ করুন:

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>

কারণ Arrayএটি একটি শ্রেণি।


1
arr = ["Jason", "Jason", "Teresa", "Judah", "Michelle", "Judah", "Judah", "Allison"]

arr.uniq.inject({}) {|a, e| a.merge({e => arr.count(e)})}

সময় কেটে গেছে 0.028 মিলিসেকেন্ড

মজার বিষয় হল, স্টুপিজেকের বাস্তবায়ন মানদণ্ডে:

সময় কেটে গেছে 0.041 মিলিসেকেন্ড

এবং বিজয়ী উত্তর:

সময় কেটে গেছে 0.011 মিলিসেকেন্ড

:)

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.