查找Ruby数组的模式(简化_

时间:2014-08-16 19:51:13

标签: ruby arrays hash

我试图找到一个数组的模式。 Mode =出现频率最高的元素。

我知道#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)

6 个答案:

答案 0 :(得分: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 :(得分:0)

在您的方法中,您首先初始化一个包含从数组的唯一值中获取的键的哈希值,并将关联的值全部设置为零。例如,数组[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],因为我们已经为数组中的每个数字创建了一个键:值对。

然而,虽然这种方法可行,但效率不高:我们不得不两次遍历数组。第一次将所有键:值对初始化为某个默认值(在本例中为零),第二次将每个数字的频率初始化。

由于每个键的默认值都是零,我们可以通过使用不同的哈希构造函数来删除初始化默认值的需要。如果我们访问不存在的密钥,myhash = {}将返回nil,但如果我们访问不存在的密钥,myhash = Hash.new(0)将返回0(请注意,您可以提供任何其他值或变量,如果需要)。

通过提供默认值零,我们可以完全摆脱第一个循环。当第二个循环找到不存在的密钥时,它将使用提供的默认值并自动初始化它。

答案 2 :(得分:0)

您可以创建hash with a default initial value

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] 

给出排序的哈希值集合中的最后一个条目,它应该是您的模式。请注意,可能有多种模式,因此您可以向后迭代,同时值部分保持不变以确定所有模式。

答案 3 :(得分:0)

def mode(array)
    array.group_by{ |e| e }.group_by{ |k, v| v.size }.max.pop.map{ |e| e.shift }
end

答案 4 :(得分:0)

使用simple_stats gem:

test = [1, 2, 3, 3, 3, 4, 5, 6, 6, 6]
test.modes #=> [3, 6]

答案 5 :(得分:0)

如果它是未排序的数组,我们可以按降序对数组进行排序

array = array.sort!

然后使用排序后的数组创建哈希默认值0,并将数组中的每个元素作为键,并将出现的次数作为值

hash = Hash.new(0)
array.each {|i| hash[i] +=1 }

如果哈希值按值(出现次数)的降序排列,则模式将是第一个元素

mode = hash.sort_by{|key, value| -value}.first[0]