Scala带有漂亮的corresponds
方法:
val a = scala.io.Source.fromFile("fileA").getLines().toSeq()
val b = scala.io.Source.fromFile("fileB").getLines().toSeq()
val areEqual = a.corresponds(b){_.equals(_)}
if(areEqual) ...
我非常喜欢这种简洁。
是否已经定义了类似的方法,它还会向我报告两个序列不同的第一个位置?
即。是否有更惯用的方式来写这样的东西:
val result = ((seqA zip seqB).zipWithIndex).find{case ((a,b),i) => !a.equals(b)} match{
case Some(((a,b),i)) => s"seqA and seqB differ in pos $i: $a <> $b"
case _ => "no difference"
}
因为你可以看到,这是颈部的血腥疼痛。如果我想使用三元组而不是元组元组,那就更糟了:
val result = (((seqA zip seqB).zipWithIndex) map {case (t,i) => (t._1,t._2,i)}).find{case (a,b,i) => !a.equals(b)} match{
case Some((a,b,i)) => s"seqA and seqB differ in pos $i: $a <> $b"
case _ => "no difference"
}
我知道diff
方法。不幸的是,那个人无视元素的顺序。
答案 0 :(得分:8)
您可以使用indexWhere
(请参阅ScalaDoc),如下所示:
(as zip bs).indexWhere{case (x,y) => x != y}
示例:
scala> val as = List(1,2,3,4)
scala> val bs = List(1,2,4,4)
scala> (as zip bs).indexWhere{case (x,y) => x != y}
res0: Int = 2
但是,请注意,如果一个Seq比另一个更长(zip
截断更长的Seq),那么基于zip
的所有解决方案都可能没有报告差异 - 这可能是您可能需要的,也可能不是。 ..
更新:对于长度相等的Seq,其他方法如下:
as.indices.find(i => as(i) != bs(i))
这很好,因为它返回Option[Int]
,所以如果Seqs之间没有差异,它会返回None
而不是魔法-1。
如果as
比bs
短,则其行为与其他解决方案相同,但如果as
更长则失败(当然,您可以采用最小长度)。
但是,因为它通过索引处理两个Seqs,所以它只能在IndexedSeq
s表现良好。
更新2 :我们可以使用lift
处理不同的Seq长度,以便在按索引检索元素时获得选项:
bs.indices.find(i => as.lift(i) != bs.lift(i))
所以,如果as = [1,2]
和bs = [1,2,3]
,它们不同的第一个索引是2(因为as
中缺少此元素)。但是,在这种情况下,我们需要在最长的Seq上调用indices
而不是最短的 - 或使用max
明确检查哪个是最长的,例如
(0 until (as.length max bs.length)).find(i => as.lift(i) != bs.lift(i))
答案 1 :(得分:3)
这好一点:
$actual = iconv("UTF-8", "ISO-8859-1//TRANSLIT", $actual);
请参阅:
(as zip bs).zipWithIndex.collectFirst { case ((a,b),i) if a!=b => i }
如果您希望输出中有def firstDiff[A,B](as: Seq[A], bs: Seq[B]) = (as zip bs).zipWithIndex.collectFirst { case ((a,b),i) if a!=b => i }
firstDiff(Seq(1,2,3,4), Seq(1,2,9,4))
// res1: Option[Int] = Some(2)
和a
:
b
另外:如果您希望它像(as zip bs).zipWithIndex.collectFirst { case ((a,b),i) if a!=b => (i,a,b) }
示例一样,您可以将其作为扩展方法:
corresponds
甚至:
implicit class Enriched_counts_TraversableOnce[A](val as: TraversableOnce[A]) extends AnyVal {
def firstDiff[B](bs: TraversableOnce[B]): Option[Int] = {
(as.toIterator zip bs.toIterator)
.zipWithIndex
.collectFirst { case ((a,b),i) if a!=b => i }
}
}
Seq(1,2,3,4).firstDiff(Seq(1,2,9,4))
// res2: Option[Int] = Some(2)