我认为这个答案之前已被问到,所以我搜索了,但我找不到任何东西。当然,有大量的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)
}
}
}
,但在实际的应用程序中,范围集可能会大得多,嵌套减少会变得非常难看。还有更好的方法吗?
答案 0 :(得分:3)
有两个正交任务,尽量不要混淆它们,因此代码仍然是模块化的。
如何构建N个数组的笛卡尔积。
如何过滤产品并计算。
使用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]]
现在做过滤器和couting:
xss.count { |x, y, z| x == 1 && z == 0 }
#=> 2
这应该稍微更加丑陋,因为我们需要使用classmethod Array::product
而不是方法Array#product
。没问题,让我们将它添加到我们的扩展模块中,最后写一下:
Array.product(0..1, 0..1, 0..1).count { |x, y, z| x == 1 && z == 0 }
#=> 2