我正在尝试找到数组的模式。模式=出现频率最高的元素。
我知道#enumerable有很多技巧,但是我还没有开始学习。我正在做的练习假设我可以解决这个问题而无需了解任何枚举。
我已经制定了游戏计划,但是我停留在第二部分。我不确定是否可以将散列键与数组进行比较,如果找到,则增加该值。
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)
myhash = Hash.new(0)
然后增加特定次数:
myhash["foo"] += 1
myhash["bar"] += 7
myhash["bar"] += 3
p myhash # {"foo"=>1, "bar"=>10}
有了这种了解,如果您替换了初始的哈希声明,然后在array.each
迭代器中进行了递增,实际上已经完成了。
myhash.sort_by{|key,value| value}[-1]
给出哈希值排序后的集合中的最后一个条目,它应该是您的模式。请注意,可能有多种模式,因此您可以向后迭代,同时值部分保持恒定以确定它们全部。
#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]
#3
h = array.each_with_object({}) { |e,h|
(h[e] || 0) += 1 } #=> {3=>2, 1=>1, 4=>2, 5=>1}
max_cnt = h.values.max #=> 2
h.select { |_,cnt| cnt == max_cnt }.keys
#=> [3, 4]
#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]
1
之后,哈希看起来像这样:{1: 1, 2: 0, 3: 0}
。您显然需要对数组中的每个值执行此操作,因此鉴于您的方法和当前的理解水平,我建议再次遍历数组:array.each do |x|
myhash[x] += 1
end
如您所见,由于我们已经为数组中的每个数字创建了一个key:value对,因此我们不需要检查myhash[k] == array[x]
。
但是,尽管这种方法行之有效,但效率不是很高:我们必须遍历数组两次。第一次将所有key:value对初始化为某个默认值(在这种情况下为零),第二次将每个数字的频率计数。由于每个键的默认值为零,我们可以通过使用其他哈希构造函数来消除初始化默认值的需要。如果我们访问不存在的键,
myhash = {}
将返回nil
,但是如果我们访问不存在的键,myhash = Hash.new(0)
将返回0
(请注意,如果需要,您可以提供任何其他值或变量)。通过提供默认值零,我们可以完全摆脱第一个循环。当第二个循环找到不存在的键时,它将使用提供的默认值并自动对其进行初始化。
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 = hash.sort_by{|key, value| -value}.first[0]