Ruby on rails 我试图在Ruby Array类的每次运行中添加一个方法,该方法接受一个需要两个参数的代码块

Ruby on rails 我试图在Ruby Array类的每次运行中添加一个方法,该方法接受一个需要两个参数的代码块,ruby-on-rails,ruby,rubygems,Ruby On Rails,Ruby,Rubygems,在Ruby数组类中添加一个每次运行的方法,该类接受一个需要两个参数的代码块。它为数组中相等项的每个连续运行调用一次代码块,发送运行长度和重复的项。输出如下所示: irb(main):001:0> load("eachrun.rb") => true irb(main):002:0> [5,9,3,4,4,4,7,8,8].each_run { |n,x| irb(main):003:1* print x, " appearing ", n, " t

在Ruby数组类中添加一个每次运行的方法,该类接受一个需要两个参数的代码块。它为数组中相等项的每个连续运行调用一次代码块,发送运行长度和重复的项。输出如下所示:

irb(main):001:0> load("eachrun.rb")    
=> true    
irb(main):002:0> [5,9,3,4,4,4,7,8,8].each_run { |n,x|    
irb(main):003:1*    print x, " appearing ", n, " times\n" }    
5 appearing 1 times    
9 appearing 1 times    
3 appearing 1 times    
4 appearing 3 times    
7 appearing 1 times    
8 appearing 2 times    
=> nil

这可能会给你一些关于如何继续的想法:

irb(main):001:0> a = [5,9,3,4,4,4,7,8,8]
=> [5, 9, 3, 4, 4, 4, 7, 8, 8]
irb(main):002:0> a.uniq.each { |e| printf("%d appears %d times\n", e, a.count(e)) }
5 appears 1 times
9 appears 1 times
3 appears 1 times
4 appears 3 times
7 appears 1 times
8 appears 2 times

我同意使用uniq和each的建议,但这只是在需要将uniq值作为数组返回的情况下。有很多方法可以迭代,这取决于你自己,但这里的关键是猴子补丁和产生你的值,以便使用块




资料来源:

我将使用
groupby
并生成相关组的键和大小

def each_run
  group_by(&:itself).map {|k,v| yield v.length, k }
end
不过,我不会将它直接修补到
数组中。首先,作为
可枚举
的一部分,它更有意义,其次,猴子补丁可能会变得混乱。不过,你可以把它做得更精致。遗憾的是,您只能优化类,而不能优化模块,因此它回到了
Array
而不是
Enumerable

module EachRun 
  refine Array do 
    def each_run 
      group_by(&:itself).map {|k,v| yield v.length, k }
    end
  end
end

然后,只需将
使用EachRun
放在您希望能够使用新方法的任何代码的顶部。

我了解了问题的意图“它为数组中相同项的每个连续运行调用代码块一次”因为示例列表不包含数字的后续运行,所以您可以忽略输入列表的结构,只计算任何给定项目出现的次数,所以示例列表是一种误导。如果例子是:

[5,9,3,4,4,4,7,8,8,5,5]
那么,打印“5出现3次”并不表明自己是正确的

我已经有一段时间没有写任何Ruby了,所以这可能不是最优的,但这正是我想到的:

require 'test/unit/assertions'
include Test::Unit::Assertions

module Enumerable

  def runs
    if empty?
      []
    else
      runs = [[first,1]]
      self[1..-1].each do |item|
        if item == runs.last.first
          runs = runs[0..-2] + [[item,runs.last.last+1]]
        else
          runs = runs + [[item,1]]
        end
      end
      runs
    end
  end

  def each_run(&block)
    runs.each(&block)
  end
end

assert_equal( [], [].runs )
assert_equal( [[5,1],[9,1],[3,1],[4,3],[7,1],[8,2],[5,2]], [5,9,3,4,4,4,7,8,8,5,5].runs )

[5,9,3,4,4,4,7,8,8,5,5].each_run do |m,n|
  puts "#{m} appears #{n} times"
end
输出

> 5 appears 1 times
> 9 appears 1 times
> 3 appears 1 times
> 4 appears 3 times
> 7 appears 1 times
> 8 appears 2 times
> 5 appears 2 times
当我在Clojure中思考时,我想到的是:

(defn runs [l]
  (reduce (fn [memo [x n :as e]]
            (let [[last-x last-n] (last memo)]
              (if (= x last-x)
                (conj (vec (drop-last memo)) [x (inc last-n)])
                (conj memo e))))
          [] (map (fn [e] [e 1]) l)))

(runs [5 5 9 8 1 1 4 3 3 3 3 5 5 5 2 2])
=> [[5 2] [9 1] [8 1] [1 2] [4 1] [3 4] [5 3] [2 2]]

很好,祝你好运
> 5 appears 1 times
> 9 appears 1 times
> 3 appears 1 times
> 4 appears 3 times
> 7 appears 1 times
> 8 appears 2 times
> 5 appears 2 times
(defn runs [l]
  (reduce (fn [memo [x n :as e]]
            (let [[last-x last-n] (last memo)]
              (if (= x last-x)
                (conj (vec (drop-last memo)) [x (inc last-n)])
                (conj memo e))))
          [] (map (fn [e] [e 1]) l)))

(runs [5 5 9 8 1 1 4 3 3 3 3 5 5 5 2 2])
=> [[5 2] [9 1] [8 1] [1 2] [4 1] [3 4] [5 3] [2 2]]