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

使用Scala在文本中查找单词对最优雅的方法是什么?,scala,pattern-matching,Scala,Pattern Matching,给出一个单词对列表 val terms = ("word1a", "word1b") :: ("word2a", "word2b") :: ... :: Nil Scala中测试文本中是否至少有一对出现的最优雅的方法是什么?测试应在第一场比赛中尽快结束。你将如何解决这个问题 编辑:更准确地说,我想知道一对词中的两个词是否出现在文本中不一定按顺序排列的地方。如果列表中的一对是这种情况,则该方法应返回true。不必返回匹配的对,如果有多对匹配,也不重要 scala> val text = S

给出一个单词对列表

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
编辑:请注意,使用集合来表示文本中的标记可以使从包含中进行的查找更加高效。你不会希望使用像列表这样的顺序

编辑2:更新要求中的澄清

编辑3:更改内容以根据评论中的建议应用

编辑:请注意,使用集合来表示文本中的标记可以使从包含中进行的查找更加高效。你不会希望使用像列表这样的顺序

编辑2:更新要求中的澄清

编辑3:更改内容以根据评论中的建议应用编辑-似乎您问题的模糊措辞意味着我回答了不同的问题:

因为你本质上是在要求这两个中的任何一个;你不妨把所有这些都放在一个大集合里

val words = (Set.empty[String] /: terms) { case (s, (w1, w2)) => s + w1 + w2 }
那么你只是在问文本中是否存在以下内容:

text.split("\\s") exists words
这很快,因为我们可以使用集合的结构快速查找文本中是否包含单词;由于以下原因,它提前终止:

scala> val text = "blah1  blah2 word2b"
text: java.lang.String = blah1  blah2 word2b
如果文本很长,您可能希望对其进行流式处理,以便延迟计算下一个要测试的单词,而不是将字符串拆分为前面的子字符串:

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
编辑-您的问题措辞含糊不清,似乎意味着我回答了另一个问题:

因为你本质上是在要求这两个中的任何一个;你不妨把所有这些都放在一个大集合里

val words = (Set.empty[String] /: terms) { case (s, (w1, w2)) => s + w1 + w2 }
那么你只是在问文本中是否存在以下内容:

text.split("\\s") exists words
这很快,因为我们可以使用集合的结构快速查找文本中是否包含单词;由于以下原因,它提前终止:

scala> val text = "blah1  blah2 word2b"
text: java.lang.String = blah1  blah2 word2b
如果文本很长,您可能希望对其进行流式处理,以便延迟计算下一个要测试的单词,而不是将字符串拆分为前面的子字符串:

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)))
您可以通过将所有术语放在一个集合中来进一步改进,甚至不必检查单词pairlist,除非文本中的单词在该集合中

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

我假设这两个元素都必须出现在文本中,但无论出现在何处,也不管出现哪一对

我不确定这是最优雅的,但也不错,如果你认为文本可能有单词,因此你不需要阅读所有的单词,并且如果你能生成一个迭代器,一次给你一个单词,那么它的速度相当快:

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)))
您可以通过将所有术语放在一个集合中来进一步改进,甚至不必检查单词pairlist,除非文本中的单词在该集合中

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


关于你的问题,有一件事是模棱两可的:你要求的结果是一个列表[布尔值],即每对布尔值,还是一个布尔值?关于你的问题,有一件事是模棱两可的:你要求的结果是一个列表[布尔值],即每对布尔值,还是一个布尔值?你是对的,这两个词都应该出现在文本的某个地方,但不一定按顺序出现。在这一点上,我更新了问题,使之更加准确。你是对的,两个词都应该出现在文本的某个地方,但不一定按顺序出现。在这一点上,我更新了这个问题,使之更加精确。这个解决方案有效,而且看起来非常简短。将文本作为一组标记获取是一个好主意。由于集合本身是函数,您可以将代码进一步压缩为texta&&textb。这不符合您作为集合读取整个文本所需的“尽快终止”标准,这意味着您保证一次读取全部文本。但是,它符合优雅标准。@Rex Kerr:这取决于您如何定义终止
尽可能快:它可以浏览整个文本,但只查看尽可能多的对。根据数据的长度、重复字数、对数等,很难说哪一个是首选的快速失败条件。@missingfaktor:Good call。谢谢。这个解决方案很有效,而且看起来很短。将文本作为一组标记获取是一个好主意。由于集合本身是函数,您可以将代码进一步压缩为texta&&textb。这不符合您作为集合读取整个文本所需的“尽快终止”标准,这意味着您保证一次读取全部文本。但是,它符合优雅标准。@Rex Kerr:这取决于您如何尽快定义terminate:它可以在整个文本中移动,但只能查看尽可能多的对。根据数据的长度、重复字数、对数等,很难说哪一个是首选的快速失败条件。@missingfaktor:Good call。谢谢。对不起,如果问题一开始就有误导性。对不起,如果问题一开始就有误导性。