繁体   English   中英

在 Scala 的文本中查找单词对的最优雅方法是什么?

[英]What's the most elegant way to find word pairs in a text with Scala?

给定一个单词对列表

val terms = ("word1a", "word1b") :: ("word2a", "word2b") :: ... :: Nil

Scala 中测试文本中是否至少有一对出现的最优雅的方法是什么? 测试应在遇到第一场比赛时尽快终止。 你会怎么解决?

编辑:更准确地说,我想知道一对单词是否出现在文本中的某个地方(不一定按顺序)。 如果列表中的一对是这种情况,则该方法应返回true 没有必要返回匹配的对,如果超过一对匹配也不重要。

scala> val text = Set("blah1", "word2b", "blah2", "word2a")
text: scala.collection.immutable.Set[java.lang.String] = Set(blah1, word2b, blah2)

scala> terms.exists{case (a,b) => text(a) && text(b)}
res12: Boolean = true

编辑:请注意,使用集合来表示文本中的标记会使contains的查找更加有效。 您不想为此使用诸如 List 之类的顺序。

编辑2:更新以澄清要求!

编辑 3:更改contains以根据评论中的建议apply

编辑 - 似乎您问题的含糊措辞意味着我回答了一个不同的问题

因为您本质上是在要求这对中的任何一个; 您不妨将所有这些扁平化为一个大集合。

val words = (Set.empty[String] /: terms) { case (s, (w1, w2)) => s + w1 + w2 }

然后您只是询问文本中是否存在这些中的任何一个:

text.split("\\s") exists words

这很快,因为我们可以使用Set的结构来快速查找单词是否包含在文本中; 由于“存在”,它提前终止:

scala> val text = "blah1  blah2 word2b"
text: java.lang.String = blah1  blah2 word2b

如果您的文本很长,您可能希望Stream它,以便懒惰地计算下一个要测试的单词,而不是预先将字符串拆分为子字符串:

scala> val Word = """\s*(.*)""".r
Word: scala.util.matching.Regex = \s*(.*)

scala> def strmWds(text : String) : Stream[String] = text match {
     | case Word(nxt) => val (word, rest) = nxt span (_ != ' '); word #:: strmWds(rest)
     | case _         => Stream.empty
     | }
strmWds: (text: String)Stream[String]

现在你可以:

scala> strmWds(text) exists words
res4: Boolean = true

scala> text.split("\\s") exists words
res3: Boolean = true

我假设这元素的两个元素都必须出现在文本中,但在哪里都没有关系,哪对出现也没有关系。

我不确定这是最优雅的,但它还不错,如果您期望文本可能包含单词(因此您不需要阅读所有内容)并且您可以生成一个迭代器,一次给你一个单词:

case class WordPair(one: String, two: String) {
  private[this] var found_one, found_two = false
  def check(s: String): Boolean = {
    if (s==one) found_one = true
    if (s==two) found_two == true
    found_one && found_two
  }
  def reset {
    found_one = false
    found_two = false
  }
}

val wordpairlist = terms.map { case (w1,w2) => WordPair(w1,w2) }

// May need to wordpairlist.foreach(_.reset) first, if you do this on multiple texts
text.iterator.exists(w => wordpairlist.exists(_.check(w)))

您可以通过将所有术语放在一个集合中来进一步改进事情,甚至无需检查单词对列表,除非文本中的单词在该集合中。

如果您的意思是单词必须按顺序相邻出现,则应将check更改为

def check(s: String) = {
  if (found_one && s==two) found_two = true
  else if (s==one) { found_one = true; found_two = false }
  else found_two = false
  found_one && found_two
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM