问题
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".)
回答1:
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
回答2:
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
回答3:
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)
回答4:
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
回答5:
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
回答6:
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
来源:https://stackoverflow.com/questions/6993848/comparing-sequences-in-ruby