如何在表达式中分发元素?

时间:2013-06-17 18:24:49

标签: ruby algorithm distribution

给出一个表达式:

(A OR B) AND (C OR D) AND (X OR Y OR Z)

我需要分发和生成组合ACXACYACZADXADYADZ,{{1} },BCXBCYBCZBDXBDY。我们有一个用户用来生成上述表达式的UI。在后端,我们需要生成不同的组合,以便更容易地匹配一组元素,如ACX,ACY等。

具有AND的组的数量不固定,每个AND组中的元素的大小也不同。

关于如何完成这项工作的想法是什么?我试图用递归编写它,并试图看看其他人是否有更聪明的答案或是否存在库。

4 个答案:

答案 0 :(得分:6)

尝试:

AB = %w[A B]
CD = %w[C D]
XYZ = %w[X Y Z]

AB.product(CD, XYZ).join(&:map)

返回如下数组:

[
  "ACX",
  "ACY",
  "ACZ",
  "ADX",
  "ADY",
  "ADZ",
  "BCX",
  "BCY",
  "BCZ",
  "BDX",
  "BDY",
  "BDZ"
]

Ruby的Array.product文档说:

------------------------------------------------------------------------------
  ary.product(other_ary, ...)                -> new_ary
  ary.product(other_ary, ...) { |p| block }  -> ary


------------------------------------------------------------------------------

Returns an array of all combinations of elements from all arrays. The length of
the returned array is the product of the length of self and the argument
arrays. If given a block, product will yield all combinations and
return self instead.

  [1,2,3].product([4,5])     #=> [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
  [1,2].product([1,2])       #=> [[1,1],[1,2],[2,1],[2,2]]
  [1,2].product([3,4],[5,6]) #=> [[1,3,5],[1,3,6],[1,4,5],[1,4,6],
                             #    [2,3,5],[2,3,6],[2,4,5],[2,4,6]]
  [1,2].product()            #=> [[1],[2]]
  [1,2].product([])          #=> []

您的问题特别感兴趣的是第三个例子。

答案 1 :(得分:2)

这不是完整的方法,但我将使用Array#product慢慢地这样做。给我一些时间。

a1 = ['A','B']
a2 = ['C','D'] 
a3 = ['X','Y','Z']

a1.product(a2).product(a3)
# => [[["A", "C"], "X"],
#     [["A", "C"], "Y"],
#     [["A", "C"], "Z"],
#     [["A", "D"], "X"],
#     [["A", "D"], "Y"],
#     [["A", "D"], "Z"],
#     [["B", "C"], "X"],
#     [["B", "C"], "Y"],
#     [["B", "C"], "Z"],
#     [["B", "D"], "X"],
#     [["B", "D"], "Y"],
#     [["B", "D"], "Z"]]

以下是完整的解决方案(我使用Array作为数据结构来保留所有结果组合):

a1.product(a2).map(&:join).product(a3).map(&:join)
# => ["ACX",
#     "ACY",
#     "ACZ",
#     "ADX",
#     "ADY",
#     "ADZ",
#     "BCX",
#     "BCY",
#     "BCZ",
#     "BDX",
#     "BDY",
#     "BDZ"]

更简单的方法是:

a1.product(a2,a3).map(&:join)
# => ["ACX",
#     "ACY",
#     "ACZ",
#     "ADX",
#     "ADY",
#     "ADZ",
#     "BCX",
#     "BCY",
#     "BCZ",
#     "BDX",
#     "BDY",
#     "BDZ"]

答案 2 :(得分:0)

您可以在一般情况下使用递归下降解析器处理此问题:

def expression(stream)
  ret = primary(stream);
  while stream.length > 0 && stream[0] != ")"
    token = stream.shift
    if token == "AND"
      ret = ret.product(primary(stream)).map(&:join)
    elsif token == "OR"
      ret += primary(stream);
    elsif token == "("
      raise "unexpected ("
    end
  end
  return ret
end

def primary(stream) 
  if stream[0] == "("
    stream.shift
    ret = expression(stream)
    raise ") expected" unless stream.shift == ")"
  elsif stream[0] == ")"
    raise "unexpected )"
  else
    ret = [ stream.shift ];
  end
  return ret
end

def parse(str)
  return expression(str.scan(/\)|\(|\w+/))
end

parse('(A OR B) AND (C OR D) AND (X OR Y OR Z)')

=> ["ACX", "ACY", "ACZ", "ADX", "ADY", "ADZ", 
    "BCX", "BCY", "BCZ", "BDX", "BDY", "BDZ"]

答案 3 :(得分:-3)

如果您的意思是ANDOR作为逻辑连接词andor,那么这是不可能的。 表达式(A OR B) AND (C OR D) AND (X OR Y OR Z)具有特定的单个值。你无法进​​入它。