查找Ruby数组的模式(简化)_
我试图找到数组的模式。模式=出现频率最高的元素 我知道#enumerable有很多诀窍,但我的学习还没有做到。我正在做的练习假设我可以在不了解enumerable的情况下解决这个问题 我已经写好了我的游戏计划,但我还停留在第二部分。我不确定是否可以将哈希键与数组进行比较,如果找到,则增加值查找Ruby数组的模式(简化)_,ruby,arrays,hash,Ruby,Arrays,Hash,我试图找到数组的模式。模式=出现频率最高的元素 我知道#enumerable有很多诀窍,但我的学习还没有做到。我正在做的练习假设我可以在不了解enumerable的情况下解决这个问题 我已经写好了我的游戏计划,但我还停留在第二部分。我不确定是否可以将哈希键与数组进行比较,如果找到,则增加值 def mode(array) # Push array elements to hash. Hash should overwrite dup keys. myhash = {} ar
def mode(array)
# Push array elements to hash. Hash should overwrite dup keys.
myhash = {}
array.each do |x|
myhash[x] = 0
end
# compare Hash keys to Array. When found, push +=1 to hash's value.
if myhash[k] == array[x]
myhash[k] += 1
end
# Sort hash by value
# Grab the highest hash value
# Return key(s) per the highest hash value
# rejoice!
end
test = [1, 2, 3, 3, 3, 4, 5, 6, 6, 6]
mode(test) # => 3, 6 (because they each appear 3 times)
在您的方法中,您首先初始化了一个散列,其中包含从数组的唯一值中提取的键,关联的值都设置为零。例如,数组
[1,2,2,3]
将创建散列{1:0,2:0,3:0}
在此之后,您计划通过将散列中关联键的值为每个实例增加1来计算数组中每个值的实例数。因此,在找到数组中的编号1
后,散列将如下所示:{1:1,2:0,3:0}
。您显然需要对数组中的每个值执行此操作,因此,考虑到您的方法和当前的理解水平,我建议再次循环数组:
array.each do |x|
myhash[x] += 1
end
如您所见,我们不需要检查myhash[k]==array[x]
,因为我们已经为数组中的每个数字创建了一个key:value对
然而,虽然这种方法可以工作,但效率不是很高:我们必须在数组中循环两次。第一次是将所有键:值对初始化为某个默认值(在本例中为零),第二次是计算每个数字的频率
由于每个键的默认值将为零,我们可以通过使用不同的哈希构造函数来消除初始化默认值的需要。myhash={}
如果访问不存在的键,将返回nil
,但是myhash=hash。如果访问不存在的键,则新(0)
将返回0
(请注意,如果需要,您可以提供任何其他值或变量)
通过提供默认值零,我们可以完全摆脱第一个循环。当第二个循环发现一个不存在的键时,它将使用提供的默认值并自动初始化它。您可以创建一个:
然后增加特定事件:
myhash["foo"] += 1
myhash["bar"] += 7
myhash["bar"] += 3
p myhash # {"foo"=>1, "bar"=>10}
有了这样的理解,如果您替换初始哈希声明,然后在数组中进行递增,那么每个迭代器实际上都完成了
myhash.sort_by{|key,value| value}[-1]
给出已排序的哈希值集中的最后一个条目,这应该是您的模式。请注意,可能有多种模式,因此您可以在值部分保持不变的情况下向后迭代以确定所有模式。有很多种方法可以做到这一点。以下是一些方法
def mode(array)
array.group_by{ |e| e }.group_by{ |k, v| v.size }.max.pop.map{ |e| e.shift }
end
#1
array = [3,1,4,5,4,3]
a = array.uniq #=> [3, 1, 4, 5]
.map {|e| [e, array.count(e)]}
#=> [[3, 2], [1, 1], [4, 2], [5, 1]]
.sort_by {|_,cnt| -cnt} #=> [[3, 2], [4, 2], [1, 1], [5, 1]]
a.take_while {|_,cnt| cnt == a.first.last}
#=> [[3, 2], [4, 2]]
.map(&:first) #=> [3, 4]
#2
array.sort #=> [1, 3, 3, 4, 4, 5]
.chunk {|e| e}
#<Enumerator: #<Enumerator::Generator:0x000001021820b0>:each>
.map { |e,a| [e, a.size] } #=> [[1, 1], [3, 2], [4, 2], [5, 1]]
.sort_by { |_,cnt| -cnt } #=> [[4, 2], [3, 2], [1, 1], [5, 1]]
.chunk(&:last)
#<Enumerator: #<Enumerator::Generator:0x00000103037e70>:each>
.first #=> [2, [[4, 2], [3, 2]]]
.last #=> [[4, 2], [3, 2]]
.map(&:first) #=> [4, 3]
#4
a = array.group_by { |e| e } #=> {3=>[3, 3], 1=>[1], 4=>[4, 4], 5=>[5]}
.map {|e,ees| [e,ees.size]}
#=> [[3, 2], [1, 1], [4, 2], [5, 1]]
max = a.max_by(&:last) #=> [3, 2]
.last #=> 2
a.select {|_,cnt| cnt == max}.map(&:first)
#=> [3, 4]
使用simple_stats
gem:
test = [1, 2, 3, 3, 3, 4, 5, 6, 6, 6]
test.modes #=> [3, 6]
如果是未排序的数组,我们可以按降序对数组进行排序
array = array.sort!
然后使用排序数组创建哈希默认值0,数组的每个元素作为键,出现次数作为值
hash = Hash.new(0)
array.each {|i| hash[i] +=1 }
如果哈希按值的降序排序(出现次数),则mode将是第一个元素
请定义“模式”,包括数组是[1,1,2,2]
的情况。另外,您的示例有一个有序数组。数组是从最小到最大排序的吗?请在提问时尽量完整和精确。我很抱歉。通过“模式”,我正在查找元素出现频率最高的。在本例中,答案为3和6(每个出现3次)。你提出了一个很好的观点-我可能还需要建立一个.sort来处理任何非有序数组。CJ,在澄清时,最好编辑你的问题,而不是在注释中解释,因为不是每个人都阅读后者。无论何时编辑,你都不应该更改以前的内容。相反,请确定编辑。一些SO成员写道:“编辑:…”.不必在你问题的结尾。
array = array.sort!
hash = Hash.new(0)
array.each {|i| hash[i] +=1 }
mode = hash.sort_by{|key, value| -value}.first[0]