【问题标题】:Iterate set covered by cross-product of ranges in ruby迭代由 ruby​​ 中范围的叉积覆盖的集合
【发布时间】:2011-02-19 14:26:47
【问题描述】:

我想以前有人问过这个答案,所以我搜索了,但找不到任何东西。当然,有很多 Ruby Array 问题,所以它可能就在那里,只是被埋没了。

在任何情况下,我都试图减少范围的叉积,返回满足某些条件的叉积的所有元素的总和。构建一个简单的例子,如果我有一个这样的数组:

[0..1,0..1,0..1]

我想迭代这个集合:

[
  [0,0,0],
  [0,0,1],
  [0,1,0],
  [0,1,1],
  [1,0,0],
  [1,0,1],
  [1,1,0],
  [1,1,1]
]

并根据条件“return 1 if i[0] == 1 and i[2] == 0”返回一个总和(这将给出 2)。在我设计的示例中,我可以这样做:

br = 0..1

br.reduce(0){|sumx, x|
  sumx + br.reduce(0){|sumy, y|
    sumy + br.reduce(0){|sumz, z|
      sumz + (x == 1 and z == 0 ? 1 : 0)
    }
  }
}

,但是在实际应用中,范围的集合可能会更大,嵌套减少这种方式会变得非常难看。有没有更好的办法?

【问题讨论】:

    标签: ruby arrays iteration cross-product


    【解决方案1】:

    有两个正交任务,尽量不要把它们混在一起,这样代码就保持模块化。

    1. 如何构建 N 个数组的笛卡尔积。

    2. 如何过滤产品和计数。

    使用Array#product 得到笛卡尔积:

    xs = [0..1, 0..1, 0..1].map(&:to_a)
    xss = xs[0].product(*xs[1..-1]) # or xs.first.product(*xs.drop(1))
    #=> [[0, 0, 0], [0, 0, 1], [0, 1, 0], ..., [1, 1, 0], [1, 1, 1]]
    

    现在进行过滤和计算:

    xss.count { |x, y, z| x == 1 && z == 0 }
    #=> 2
    

    这有点难看,因为我们需要类方法Array::product 而不是方法Array#product。没问题,我们将它添加到我们的扩展模块中,最后编写:

    Array.product(0..1, 0..1, 0..1).count { |x, y, z| x == 1 && z == 0 }
    #=> 2
    

    【讨论】:

    • 谢谢,就是这样。我知道构建笛卡尔积,但感谢数组折叠的解决方案,我忘记了块可以通过这种方式将数组拆分为参数。
    猜你喜欢
    • 2016-08-04
    • 1970-01-01
    • 2014-09-08
    • 1970-01-01
    • 1970-01-01
    • 2019-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多