【问题标题】:Idiomatic ruby for generating permutations?用于生成排列的惯用红宝石?
【发布时间】:2012-10-03 12:07:04
【问题描述】:

我想知道这个用于生成排列的函数的惯用版本在 Ruby 中会是什么样子。我知道[1,2,3].permutation.to_a 会产生相同的结果,但我对学习 Ruby 以及如何在 Ruby 中解决此类递归问题更感兴趣。

def permutations(seq)
    if seq.empty? || seq.count == 1
        seq
    else
        seq.map { |x|
            permutations(seq.select { |e| e != x }).map { |p|
                if p.class == Fixnum
                    [x, p]
                else
                    p.unshift(x)
                end
            }
        }.flatten(1)
    end
end

谢谢!

【问题讨论】:

  • 您可以将if 简化为case (p)when Fixnum

标签: ruby recursion idioms


【解决方案1】:
class Array
  def permutations
    return [self] if size < 2
    perm = []
    each { |e| (self - [e]).permutations.each { |p| perm << ([e] + p) } }
    perm
  end
end 

[1, 2, 3].permutations #=> [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] 

来源:http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/32844

编辑:为避免猴子补丁,将其放入模块中:

module ArrayExtensions
  def permutations
    #snip
  end
end

Array.send :include, ArrayExtensions

【讨论】:

  • 非常简洁明了。一般来说,这是红宝石的方式——在不存在此类行为时向对象添加行为?网址中的示例(令人着迷!)来自闲聊世界。
  • 是的 - 如果该方法仅用于单个类,我会将其放在该类中。否则,您将不必要地使用if x.is_a? Array 等使您的代码混乱。
  • drsnyder:它被称为猴子补丁,这是一篇很棒的博文codinghorror.com/blog/2008/07/monkeypatching-for-humans.html
  • @drsnyder:不修改核心类的另一种方法:stackoverflow.com/a/12864516/1004889
  • 如果你想避免猴子补丁,更简洁的方法是将其放入模块中,然后使用.send :include,请参阅编辑。
【解决方案2】:

在 Ruby(尤其是 Rails)中,将这样的功能直接添加到核心类是很常见的。

该方法的一种替代方法是单独的静态实用程序模块:

module ArrayUtils
  def self.permute(array)
    return [array] if array.size < 2

    array.flat_map do |elem|
      permute(array - [elem]).map do |perm|
        ([elem] + perm)
      end
    end
  end
end

ArrayUtils.permute [1, 2, 3]
# => [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-21
    • 2019-08-09
    • 1970-01-01
    相关资源
    最近更新 更多