【问题标题】:Scala string manipulationScala 字符串操作
【发布时间】:2016-03-17 23:54:54
【问题描述】:

我有以下 Scala 代码:

val res = for {
  i <- 0 to 3
  j <- 0 to 3
  if (similarity(z(i),z(j)) < threshold) && (i<=j)
} yield z(j)  

这里的z代表Array[String]similarity(z(i),z(j))计算两个字符串之间的相似度。

这个问题的工作原理是计算第一个字符串和所有其他字符串之间的相似度,然后计算第二个字符串和所有其他字符串之间的相似度,除了先计算第三个字符串的相似度,然后再计算第三个字符串的相似度,以此类推。

我的要求是,如果第 1 个字符串与第 3 个、第 4 个和第 8 个字符串匹配,那么 所有这 3 个字符串不应该进一步参与循环,循环应该跳到第 2 个字符串,然后是第 5 个字符串,第 6 个字符串等等。

我被困在这一步,不知道如何继续。

【问题讨论】:

  • 我很困惑——这是关于字符串操作的问题吗?因为字符串在 Scala 中是不可变的。

标签: string scala for-loop


【解决方案1】:

我假设您的意图是保留两个相似字符串的第一个字符串(例如,如果第一个字符串与第三个、第四个和第八个字符串太相似,则只保留第一个字符串 [在这些相似字符串之外]) .

我有几种方法可以做到这一点。从某种意义上说,它们都是相反的:对于每个字符串,如果它与任何后来的字符串过于相似,那么当前的字符串将被过滤掉(而不是后来的字符串)。如果您在应用此过程之前首先反转输入数据,您会发现产生了所需的结果(尽管在结果列表下面的第一个解决方案中,结果列表本身是反转的 - 所以如果顺序很重要,您可以再次反转它):

第一种方式(可能更容易理解):

def filterStrings(z: Array[String]) = {
  val revz = z.reverse
  val filtered = for {
    i <- 0 to revz.length if !revz.drop(i+1).exists(zz => similarity(zz, revz(i)) < threshold)
  } yield revz(i)
  filtered.reverse // re-reverses output if order is important
}

'drop' 调用是为了确保每个字符串只与以后的字符串进行检查。

第二个选项(功能齐全,但更难遵循):

val filtered = z.reverse.foldLeft((List.empty[String],z.reverse)) { case ((acc, zt), zz) => 
  (if (zt.tail.exists(tt => similarity(tt, zz) < threshold)) acc else zz :: acc, zt.tail) 
}._1

我将尝试解释这里发生了什么(以防您 - 或任何读者 - 不习惯跟随折叠):

这对反向输入数据使用折叠,从空字符串(累积结果)和剩余输入数据(反向)开始(用于比较 - 我将其标记为 zt 为“z-tail” )。

折叠然后循环遍历数据,根据剩余数据的尾部检查每个条目(因此它不会与自身或任何更早的条目进行比较)

如果匹配,则只允许现有的累加器(标记为acc)通过,否则,将当前条目(zz)添加到累加器中。这个更新后的累加器与“剩余”字符串 (zt.tail) 的尾部配对,以确保可以比较的缩减集。

最后,我们得到了一对列表:所需的剩余字符串和一个空列表(没有剩余的字符串可供比较),因此我们将其中的第一个作为结果。

【讨论】:

  • 如果我必须在第一次迭代后将所有字符串保持在一个集合中,然后在第二次迭代后我应该有第二组相似字符串等等,该怎么办? @Shadowlands
【解决方案2】:

如果我理解正确,您希望循环遍历数组的元素,将每个元素与后面的元素进行比较,然后删除太相似的元素。

你不能(很容易)在一个简单的循环中做到这一点。您需要跟踪哪些项目已被过滤掉,这将需要另一个布尔数组,您可以随时更新和测试。这不是一个糟糕的方法,而且效率很高,但它并不美观或实用。

所以你需要使用递归函数,而这种事情最好使用不可变的数据结构来完成,所以还是坚持List吧。

def removeSimilar(xs: List[String]): List[String] = xs match {
  case Nil     => Nil
  case y :: ys => y :: removeSimilar(ys filter {x => similarity(y, x) < threshold})
}

这是一个简单的递归函数。不多解释:如果xs 为空,则返回空列表,否则将列表的头部添加到应用于过滤尾部的函数中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-06
    相关资源
    最近更新 更多