Ruby:如何对 Ruby 数组进行分组?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3884829/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 23:20:53  来源:igfitidea点击:

Ruby: How to group a Ruby array?

ruby-on-railsruby

提问by Matt Elhotiby

I have a Ruby array

我有一个 Ruby 数组

> list = Request.find_all_by_artist("Metallica").map(&:song)
=> ["Nothing else Matters", "Enter sandman", "Enter Sandman", "Master of Puppets", "Master of Puppets", "Master of Puppets"]

and I want a list with the counts like this:

我想要一个像这样计数的列表:

{"Nothing Else Matters" => 1,
 "Enter Sandman" => 2,
 "Master of Puppets" => 3}

So ideally I want a hash that will give me the count and notice how I have Enter Sandmanand enter sandmanso I need it case insensitive. I am pretty sure I can loop through it but is there a cleaner way?

所以理想情况下,我想要一个散列,它会给我计数并注意我的情况Enter Sandmanenter sandman所以我需要它不区分大小写。我很确定我可以循环遍历它,但是有更干净的方法吗?

回答by sepp2k

list.group_by(&:capitalize).map {|k,v| [k, v.length]}
#=> [["Master of puppets", 3], ["Enter sandman", 2], ["Nothing else matters", 1]]

The group by creates a hash from the capitalized version of an album name to an array containing all the strings in listthat match it (e.g. "Enter sandman" => ["Enter Sandman", "Enter sandman"]). The mapthen replaces each array with its length, so you get e.g. ["Enter sandman", 2]for "Enter sandman".

group by 创建从capitalize专辑名称的d 版本到包含list匹配它的所有字符串的数组的散列(例如"Enter sandman" => ["Enter Sandman", "Enter sandman"])。在map随后替换其长度每个数组,这样就可以获得如["Enter sandman", 2]"Enter sandman"

If you need the result to be a hash, you can call to_hon the result or wrap a Hash[ ]around it.

如果你需要结果是一个散列,你可以调用to_h结果或者用 a 包裹Hash[ ]它。

回答by ghostdog74

list.inject(Hash.new(0)){|h,k| k.downcase!; h[k.capitalize] += 1;h}

回答by glenn Hymanman

Another take:

另一种看法:

h = Hash.new {|hash, key| hash[key] = 0}
list.each {|song| h[song.downcase] += 1}
p h  # => {"nothing else matters"=>1, "enter sandman"=>2, "master of puppets"=>3}

As I commented, you might prefer titlecase

正如我评论的,你可能更喜欢 titlecase

回答by Harish Shetty

Grouping and sorting of a data set of unknown size in Ruby should be a choice of last resort. This is a chore best left to DB. Typically problems like yours is solved using a combination of COUNT, GROUP BY, HAVINGand ORDER BYclauses. Fortunately, rails provides a countmethod for such use cases.

在 Ruby 中对未知大小的数据集进行分组和排序应该是最后的选择。这是最好留给 DB 的苦差事。通常,像你这样的问题是使用的组合解决了COUNTGROUP BYHAVINGORDER BY条款。幸运的是,railscount为此类用例提供了一种方法。

song_counts= Request.count(
              :select => "LOWER(song) AS song"
              :group => :song, :order=> :song,
              :conditions => {:artist => "Metallica"})

song_counts.each do |song, count|
  p "#{song.titleize} : #{count}"
end

回答by ray

Late but clean answer I have,

我有迟到但干净的答案,

l = list.group_by(&:titleize)
l.merge(l) { |k,v| l[k] = v.count }

Note: If we do want unique keys i.e. without titleize, then replace it with itself

注意:如果我们确实想要唯一键,即没有titleize,则将其替换为itself

回答by BrunoFacca

As of Ruby 2.7, you can use Enumerable#tally.

从 Ruby 2.7 开始,您可以使用Enumerable#tally.

list.tally
# => {"Nothing else Matters"=>1, "Enter sandman"=>1, "Enter Sandman"=>1, "Master of Puppets"=>3}