在 Ruby 中比较序列

发布于 2024-11-28 18:21:58 字数 270 浏览 2 评论 0原文

假设我必须(中小型)数组:

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["aaa", "bbb", "ccc"]

如何确定 tokens 是否包含 template 的所有条目(按相同的顺序)?

(请注意,在上面的示例中,应忽略第一个“ccc”,从而导致由于最后一个“ccc”而导致匹配。)

Assuming I have to (small-to-medium) arrays:

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["aaa", "bbb", "ccc"]

How can I determine whether tokens contains all entries of template, in that same order?

(Note that in the example above, the first "ccc" should be ignored, resulting in a match due to the last "ccc".)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

厌倦 2024-12-05 18:21:59

这是一个单行条件:

 tokens.select {|t| t if template.include?(t)}.reverse.uniq == template.reverse \
  or \
   tokens.select {|t| t if template.include?(t)}.uniq == template

示例:

def check_order(tokens, template)
   tokens.select {|t| t if template.include?(t)}.reverse.uniq == template.reverse \
    or \
     tokens.select {|t| t if template.include?(t)}.uniq == template
end

tokens = ["aaa", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["bbb", "aaa", "ccc"]
check_order(tokens,template) # => false

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["aaa", "bbb", "ccc"]
check_order(tokens,template) # => true

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["aaa", "ccc", "bbb"]
check_order(tokens,template) # => true

This is a one-liner condition:

 tokens.select {|t| t if template.include?(t)}.reverse.uniq == template.reverse \
  or \
   tokens.select {|t| t if template.include?(t)}.uniq == template

Example:

def check_order(tokens, template)
   tokens.select {|t| t if template.include?(t)}.reverse.uniq == template.reverse \
    or \
     tokens.select {|t| t if template.include?(t)}.uniq == template
end

tokens = ["aaa", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["bbb", "aaa", "ccc"]
check_order(tokens,template) # => false

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["aaa", "bbb", "ccc"]
check_order(tokens,template) # => true

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["aaa", "ccc", "bbb"]
check_order(tokens,template) # => true
勿挽旧人 2024-12-05 18:21:59

这是另一个想法,如果阵列是中小型的,它可能会工作得很好。
它只是将标记转换为正则表达式,并尝试将模板与其进行匹配。
(这也会将空模板视为与令牌匹配,因此如果您不希望这样做,只需显式处理这个极端情况)

def tokens_in_template? tokens, *template
  re = /^#{tokens.map {|x| "(?:#{x})?"}.join}$/
  !! (template.join =~ re)
end

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
puts tokens_in_template? tokens                            # => true
puts tokens_in_template? tokens, "aaa", "bbb", "ccc"       # => true
puts tokens_in_template? tokens, "aaa", "bbb", "ccc", "aa" # => false
puts tokens_in_template? tokens, "aaa", "zzz", "ccc"       # => false
puts tokens_in_template? tokens, "aaa", "zzz"              # => true

Here's another idea, if the arrays are small-to medium, it might work fine.
It just converts the tokens into a regexp and tries to match the template against it.
(This will also treat empty template as if it matches tokens, so if you don't want that, just handle this corner case explicitly)

def tokens_in_template? tokens, *template
  re = /^#{tokens.map {|x| "(?:#{x})?"}.join}$/
  !! (template.join =~ re)
end

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
puts tokens_in_template? tokens                            # => true
puts tokens_in_template? tokens, "aaa", "bbb", "ccc"       # => true
puts tokens_in_template? tokens, "aaa", "bbb", "ccc", "aa" # => false
puts tokens_in_template? tokens, "aaa", "zzz", "ccc"       # => false
puts tokens_in_template? tokens, "aaa", "zzz"              # => true
陈甜 2024-12-05 18:21:59

如果结果为空,只需从第二个数组中减去第一个数组

result = template - tokens
if result.empty?
  #You have a match
else
  #No match
end

即可在此处阅读有关数组的更多信息 http://www.ruby-doc.org/core/classes/Array.html#M000273

如果顺序很重要,则使用 <=>上面的链接中再次描述了运算符

Just subtract the first array from the second array if the result is empty you have your match

result = template - tokens
if result.empty?
  #You have a match
else
  #No match
end

Read more about arrays here http://www.ruby-doc.org/core/classes/Array.html#M000273

If order is important then use <=> operator again described in the link above

如梦初醒的夏天 2024-12-05 18:21:58

这适用于您的示例数据。

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["aaa", "bbb", "ccc"]

pos = 0
condition_met = true
template.each do |temp|
  if (tpos = tokens[pos..-1].index temp) == nil then
    break condition_met = false
  else
    pos = tpos
  end
end

puts condition_met

This works for your sample data.

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["aaa", "bbb", "ccc"]

pos = 0
condition_met = true
template.each do |temp|
  if (tpos = tokens[pos..-1].index temp) == nil then
    break condition_met = false
  else
    pos = tpos
  end
end

puts condition_met
深者入戏 2024-12-05 18:21:58

我认为通过递归来做到这一点是最干净的:

class Array
  def align(other)
    if pos = index(other.first)
      other.size == 1 || slice(pos..-1).align(other.drop(1))
    end
  end
end

所以:

[1,2,3,4,3,2,1].align([1,2,3])
=> true
[1,2,3,4,3,2,1].align([1,4,1])
=> true
[1,2,3,4,3,2,1].align([1,4,2,3])
=> nil

Cleanest, I think, to do this via recursion:

class Array
  def align(other)
    if pos = index(other.first)
      other.size == 1 || slice(pos..-1).align(other.drop(1))
    end
  end
end

so:

[1,2,3,4,3,2,1].align([1,2,3])
=> true
[1,2,3,4,3,2,1].align([1,4,1])
=> true
[1,2,3,4,3,2,1].align([1,4,2,3])
=> nil
温柔戏命师 2024-12-05 18:21:58

manatwork 提供的解决方案很好,但对我来说,这是一个更红宝石风格的解决方案:

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["aaa", "bbb", "ccc"]

def tokens_include_template(tokens, template)
  tokens = tokens.to_enum
  template.each do |t|
    return false unless loop { break true if t == tokens.next }
  end
  true
end

puts tokens_include_template(tokens, template)

Solution provided by manatwork is good, but here is one that seems more ruby-ish to me:

tokens = ["aaa", "ccc", "xxx", "bbb", "ccc", "yyy", "zzz"]
template = ["aaa", "bbb", "ccc"]

def tokens_include_template(tokens, template)
  tokens = tokens.to_enum
  template.each do |t|
    return false unless loop { break true if t == tokens.next }
  end
  true
end

puts tokens_include_template(tokens, template)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文