我假设您的意图是保留两个相似字符串的第一个字符串(例如,如果第一个字符串与第三个、第四个和第八个字符串太相似,则只保留第一个字符串 [在这些相似字符串之外]) .
我有几种方法可以做到这一点。从某种意义上说,它们都是相反的:对于每个字符串,如果它与任何后来的字符串过于相似,那么当前的字符串将被过滤掉(而不是后来的字符串)。如果您在应用此过程之前首先反转输入数据,您会发现产生了所需的结果(尽管在结果列表下面的第一个解决方案中,结果列表本身是反转的 - 所以如果顺序很重要,您可以再次反转它):
第一种方式(可能更容易理解):
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) 的尾部配对,以确保可以比较的缩减集。
最后,我们得到了一对列表:所需的剩余字符串和一个空列表(没有剩余的字符串可供比较),因此我们将其中的第一个作为结果。