如何在Ruby中查找数组的唯一出现次数

如何在Ruby中查找数组的唯一出现次数,ruby,Ruby,我有一个数组,包含n个元素。每个元素包含两个单词 这使数组看起来像这样:[“英格兰约翰”、“英格兰本”、“美国保罗”、“英格兰约翰”] 我想找到每个国家的唯一名称的数量。例如,英格兰将有两个唯一的名字,因为约翰存在两次 到目前为止,我已经将数组分为两个数组,一个包含国家,如['England'、'Usa'、…],另一个包含名字['John'、'Paul'、…],但是我不确定从这里开始往哪里去问题是,实际上,您将这些数据存储为字符串数组。这是一个糟糕的数据结构选择,因为它使操作更加困难 例如,假设

我有一个数组,包含n个元素。每个元素包含两个单词

这使数组看起来像这样:[“英格兰约翰”、“英格兰本”、“美国保罗”、“英格兰约翰”]

我想找到每个国家的唯一名称的数量。例如,英格兰将有两个唯一的名字,因为约翰存在两次


到目前为止,我已经将数组分为两个数组,一个包含国家,如['England'、'Usa'、…],另一个包含名字['John'、'Paul'、…],但是我不确定从这里开始往哪里去

问题是,实际上,您将这些数据存储为字符串数组。这是一个糟糕的数据结构选择,因为它使操作更加困难

例如,假设我们首先将这些数据转换为散列,将每个国家映射到名称列表:

data = ['England John', 'England Ben', 'USA Paul', 'England John']

mapped_names = {}

data.each do |item|
  country, name = item.split
  mapped_names[country] ||= []
  mapped_names[country] << name
end
结果变量为:

mapped_names # => {"England"=>["John", "Ben", "John"], "USA"=>["Paul"]}
mapped_name_counts # => {"England"=>2, "USA"=>1}
如果使用ruby 2.7版尚未发布!!,最后一行代码甚至可以简化为:

mapped_name_counts = unique_names.tally(&:uniq)
一个班轮方案:

ary.uniq.group_by { |e| e.split.first }.transform_values(&:count)
#=> {"England"=>2, "USA"=>1}

比其他解决方案更详细一些,但不使用ActiveSupport提供的转换值

require "set"

data = ["England John", "England Ben", "USA Paul", "England John", "Switzerland Pascal"]

names_per_country = data.each_with_object({}) do |country_and_name, accu|
  country, name = country_and_name.split(" ")
  country_data = accu[country] ||= Set.new
  country_data << name
end

names_per_country.each do |country, names|
  puts "#{country} has #{names.size} unique name(s)"
end

# => England has 2 unique names
# => USA has 1 unique names
# => Switzerland has 1 unique names
此解决方案首先将数组转换为哈希结构,其中键是国家名称,值是集合。 我选择集合是因为它会自动处理问题的唯一部分集合不能包含重复项

之后,通过检查集合的大小,可以找到每个国家的唯一名称数。 如果需要,还可以找到集合元素的名称

arr = ['England John', 'England Ben', 'USA Paul', 'England John']
这需要两次通过数组arr.uniq作为第一次。要只通过一次,可以执行以下操作

require 'set'

uniques = Set.new
arr.each_with_object(Hash.new(0)) { |s,h| h[s[/\S+/]] += 1 if uniques.add?(s) }
  #=> {"England"=>2, "USA"=>1}
请参阅的形式,它接受一个称为默认值的参数,以及


我不清楚这两种计算中哪一种通常更快。

听起来你想使用某种多地图结构,而不是数组,其中国家是键,名称是值转换的te是ActiveSupport方法。如果您没有使用rails,可以将其替换为map{country,occurrences{country,occurrences.count]}.to_h@ndnenkov,transform_值是纯Ruby:,但对于较旧的Ruby,您的选项是ok.ndnenkov和@pascalbetz,transform_值!,变换_键和变换_键!在Ruby v2.4中首次亮相。@iGian感谢您的回复。请你解释一下不同的部分是做什么的好吗?我对{e | e.split.first}位和转换值&:count感到特别困惑bit@BenWilliams我建议您一步一步地运行代码:ari.uniq,然后ari.uniq.group_by{| e | e.split.first},依此类推|e |是包含字符串的变量,该字符串被拆分为一个数组,我们取该数组的第一个元素:a b.split.first返回a,这是用于分组的值。有关转换\u值,请参见上面的注释。看起来您从名称唯一\u名称切换到了映射的\u名称,但没有更改前一个名称的所有出现。不需要答复。您看到后,我将删除此评论。它看起来非常有用。@CarySwoveland
arr.uniq.each_with_object(Hash.new(0)) { |s,h| h[s[/\S+/]] += 1 }
  #=> {"England"=>2, "USA"=>1}
require 'set'

uniques = Set.new
arr.each_with_object(Hash.new(0)) { |s,h| h[s[/\S+/]] += 1 if uniques.add?(s) }
  #=> {"England"=>2, "USA"=>1}