2017-04-15 70 views
1

如何停止此代码输出中的重复项。Ruby循环输出重复

RE = /<("[^"]*"|'[^']*'|[^'">])*>/ 
TAG_RE = /<(.+?)>(.*?)<.+?>/ 

text = "<date>show</date> me the current conditions for <city> detroit <END>" 
a = [] 

text.scan(TAG_RE).map { |w| a<< w; } 

text.gsub(RE, '').split.each do |q| 
    a.each_with_index do |v, i| 
     if q == a[i].last.strip 
      puts "#{q}\tB-#{a[i].first}"   
     else 
      puts "#{q}\tO"   
     end 

    end 
end 

产出

show B-date 
show O 
me O 
me O 
the O 
the O 
current O 
current O 
conditions O 
conditions O 
for O 
for O 
detroit O 
detroit B-city 

我只想字的单个实例,如果他们符合条件

喜欢这个

show B-date 
me O 
the O 
current O 
conditions O 
for O 
detroit B-city 

我在哪里可以把next的循环?

编辑
这是密码Rubyiotic?

text.gsub(RE, '').split.each do |q| 
    a.each_with_index do |v, i| 
     @a = a[i].last.strip # save in a variable  
     if @a == q 
      puts "#{q}\tB-#{a[i].first}"  
      break # break inner loop if match found 
     end 
    end 
    next if @a == q #skip current outer loop if match found 
    puts "#{q}\tO" 
end 
+0

底特律应该结束''标签吗? –

+0

这并不重要。它只是检查标签内的单词,然后从开始部分获取标签名称。 – arjun

回答

2

的问题是,你还遍历您a这实际上是标签和文字之间的哈希值。

如果你对待你的scan a hash而不是array,那么你不会得到重复。

RE = /<("[^"]*"|'[^']*'|[^'">])*>/ 
TAG_RE = /<(.+?)>(.*?)<.+?>/ 

text = "<date>show</date> me the current conditions for <city> detroit <END>" 

a = text.scan(TAG_RE) 

text.gsub(RE, '').split.each do |q| 
    d = a.find { |p| p.last.strip == q } 
    if d 
    puts "#{q}\tB-#{d.first}" 
    else 
    puts "#{q}\tO" 
    end 
end 

输出:

show B-date 
me  O 
the  O 
current O 
conditions  O 
for  O 
detroit B-city 

而且,虽然我们在这,你可以使用一个正确hash

RE = /<("[^"]*"|'[^']*'|[^'">])*>/ 
TAG_RE = /<(.+?)>(.*?)<.+?>/ 

text = "<date>show</date> me the current conditions for <city> detroit <END>" 

map = Hash[*text.scan(TAG_RE).flatten.map(&:strip)].invert 

text.gsub(RE, '').split.each do |q| 
    tag = map[q] 
    if tag 
    puts "#{q}\tB-#{tag}" 
    else 
    puts "#{q}\tO" 
    end 
end 

产生相同的输出。

编辑: 如果你在一个更Ruby- 去年秋季方式想,我可能会做这样的事情:

class Text 
    TAGS_RE = /<("[^"]*"|'[^']*'|[^'">])*>/ 
    TAGS_WORDS_RE = /<(.+?)>\s*(.*?)\s*<.+?>/ 

    def self.strip_tags(text) 
    text.gsub(TAGS_RE, '') 
    end 

    def self.tagged_words(text) 
    matches = text.scan(TAGS_WORDS_RE) 
    Hash[*matches.flatten].invert 
    end 
end 

class Word 
    def self.display(word, tag) 
    puts "#{word}\t#{Word.tag(tag)}" 
    end 

    private 

    def self.tag(tag) 
    tag ? "B-#{tag}" : "0" 
    end 
end 

text = "<date>show</date> me the current conditions for <city> detroit <END>" 

words_tag = Text.tagged_words(text) 
Text.strip_tags(text).split.each do |word| 
    tag = words_tag[word] 
    Word.display(word, tag) 
end 

为什么?

我不是那么聪明,而且我很懒,所以我喜欢尽可能明确地写东西。所以,我尽量避免循环。

编写循环很容易,但是读取循环并不容易,因为在继续阅读和分析源代码时,必须保持所读内容的上下文。

通常,break s和next s的周期更难解析,因为您必须跟踪哪些代码路径突然结束周期。

嵌套循环更加困难,因为您必须跟踪以不同速度更改的多个上下文。

我相信建议的版本更容易阅读,因为每一行都可以自行理解。从一条线到另一条线,我们必须记住的环境很少。

细节被抽象的方法,所以如果你只是想了解大局,你可以看看代码的主要部分:

words_tag = Text.tagged_words(text) 
Text.strip_tags(text).split.each do |word| 
    tag = words_tag[word] 
    Word.display(word, tag) 
end 

如果你想了解它是如何的细节完成后,你看看这些方法是如何实现的。采用这种方法,实现细节不会泄漏到可能不需要的地方。

我认为这是每种编程语言的一个好习惯,而不仅仅是Ruby。

+0

贺雅。我对这个问题进行了编辑。我用了'break'和'next'。好红宝石? _BTW,你的代码很好吃。当然应该想到'哈希';)._ – arjun

+0

谢谢:)。我更新了答案以解决您的新问题。 – Gaston