【问题标题】:How do I distribute elements in an expression?如何在表达式中分配元素?
【发布时间】:2013-06-17 18:24:49
【问题描述】:

给定一个表达式:

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

我需要分发和生成组合ACXACYACZADXADYADZBCXBCYBCZ、@98765433 BDYBDZ。我们有一个用户界面,用户可以使用它来生成上述表达式。在后端,我们需要生成不同的组合,以便更轻松地与 ACX、ACY 等一组元素进行匹配。

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

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

【问题讨论】:

  • ANDOR 是什么意思? Ruby 没有这样的表达式。你的意思是逻辑andor?如果你是这个意思,那是不可能的。
  • 谢谢@sawa,我不是指任何语言的逻辑连接词——只是一种表示标准的格式。
  • 为了完整起见,接受下面@the-Tin-Man 的回答。对解决方案的动态版本感兴趣的人,请参阅stackoverflow.com/questions/5582481/…。特别是代码块头,*rest = a head.product(*rest)

标签: ruby algorithm distribution


【解决方案1】:

试试:

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([])          #=> []

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

【讨论】:

  • 天啊!您在这里复制了整个文档! :) 我只给了他链接。提供链接是个好主意,这也有助于 OP 环顾其他方法。 :))
  • 只提供链接是没有价值的它坏了。我提供了一个链接和相关部分,这是我们应该做的。
  • 链接过去因为各种原因掉了,最后又回来了。它比过去更稳定,但是,根据对 SO 的普遍共识,我们不应该只使用链接,而是引用直接内容。我喜欢走路。 "Are answers that just contain links elsewhere really “good answers”?"
  • AB.product(CD, XYZ).join(&:map) 正在给"ACXACYACZADXADYADZBCXBCYBCZBDXBDYBDZ"。因此将AB.product(CD, XYZ).join(&:map) 更改为AB.product(CD, XYZ).map(&:join)。没有调查的人继续支持你。很奇怪:)
  • 感谢您指出这一点。当我从 IRB 复制到我的编辑器进行格式化时,这两个被调换了。
【解决方案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"]

【讨论】:

  • 非常感谢有关 Array.product 的提示,我是 Ruby 新手,所以不知道。绝对使解决方案优雅。关于您的解决方案的一个问题 - 我们如何处理不同数量的数组。您的示例显示 3,但如果我们有 5 或 10,例如?
  • 为简单起见,我在示例中使用了那个。您也可以使用 - a1.product(a2,a3,a4,so on)。 :)
【解决方案3】:

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

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"]

【讨论】:

    【解决方案4】:

    如果您将ANDOR 作为逻辑连接词andor,那么这是不可能的。 表达式(A OR B) AND (C OR D) AND (X OR Y OR Z) 有一个特定的值。你不能进去。

    【讨论】:

    • 谢谢sawa,我不是指任何语言的逻辑连接词——只是一种表示标准的格式。
    • 正式表示什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-14
    • 1970-01-01
    • 2011-01-17
    相关资源
    最近更新 更多