考虑到我有:
case class X(...)
val xs: Seq[X] = ... // some method result
val ys: Seq[X] = ... // some other method result下列情况成立:
xs.distinct.sameElements(xs) // true
ys.distinct.sameElements(ys) // true我要面对的是:
xs forall(ys contains _) // true
xs.toSet subsetOf ys.toSet // false为什么?我的意思是,很明显,在重复的情况下,从Set的Seq中选择随机元素,但是因为"(...).distinct.sameElements(...)“而没有重复元素。
我当然需要更深入的了解这种平等检查.
编辑:
经过长时间的搜索,我发现了这个问题,并将其浓缩如下:
我的元素不一样,但是我必须仔细看看为什么distinct.sameElements没有抱怨。但与此同时,又出现了一个新问题:
考虑到这一点:
val rnd = scala.util.Random
def int2Label(i: Int) = "[%4s]".format(Seq.fill(rnd.nextInt(4))(i).mkString)
val s = Seq(1,2,3,4)
// as expected :
val m1: Map[Int,String] = s.map(i => (i,int2Label(i))).toMap
println(m1) // Map(5 -> [ 555], 1 -> [ ], 2 -> [ 22], 3 -> [ ])
println(m1) // Map(5 -> [ 555], 1 -> [ ], 2 -> [ 22], 3 -> [ ])
// but accessing m2 several times yields different results. Why?
val m2: Map[Int,String] = s.map(i => (i,i)).toMap.mapValues { int2Label(_) }
println(m2) // Map(5 -> [ 5], 1 -> [ 11], 2 -> [ 22], 3 -> [ 333])
println(m2) // Map(5 -> [ 55], 1 -> [ 11], 2 -> [ ], 3 -> [ ])所以我的元素在我的第一序列中是不一样的,因为它们依赖于m2-construct,所以每次访问它们时,它们都是不同的。
我的新问题是,为什么m2的行为与m1不同,尽管两者都是不可变的映射。这对我来说不是直觉上的。
发布于 2011-03-26 12:09:12
造成这一领域问题的最常见的原因是测试集相等之类的。
hashCode不符合equalshashCode不符合当前的equals)原因是这很重要,因为distinct和toSet使用哈希代码构建集合,而contains只是使用exists运行集合。
xs forall(ys contains _) == xs forall (x => ys exists (y => x==y) )这变得更加复杂,因为许多集合直到它们大于最小大小(通常是4)时才开始使用散列代码,所以在测试中并不总是注意到这一点。但让我们证明给自己看:
class Liar(s: String) {
override def equals(o: Any) = o match {
case l: Liar => s == l.s
case _ => _
}
// No hashCode override!
}
val strings = List("Many","song","lyrics","go","na","na","na","na")
val lies = strings.map(s => new Liar(s))
val truly_distinct = lies.take(5)
lies.length // 8
lies.distinct.length // 8!
lies.toSet.size // 8!
lies forall( truly_distinct contains _ ) // True, because it's true
lies.toSet subsetOf truly_distinct.toSet // False--not even the same size!好的,现在我们知道,对大多数这些操作来说,匹配hashCode和equals是一件好事。
警告:在Java中,即使是原语也经常发生不匹配:
new java.lang.Float(1.0) == new java.lang.Integer(1) // True
(new java.lang.Float(1.0)).hashCode == (new java.lang.Integer(1)).hashCode // Uh-oh但是Scala现在至少捕捉到了这一点(希望每次都这样):
(new java.lang.Float(1.0)).## == (new java.lang.Integer(1)).## // WhewCase类也正确地完成了这一任务,因此我们有三种可能
equals,而不是hashCode来匹配G 229
第一个很简单。
第二个问题似乎是您的问题,这是因为mapValues实际上创建了原始集合的视图,而不是新的集合。(filterKeys也会这样做。)就我个人而言,我认为这是一个有问题的设计选择,因为通常当你有一个视图,你想要做一个单一的具体实例,你.force它。但是默认映射没有.force,因为它们没有意识到它们可能是视图。所以你不得不求助于
myMap.map{ case (k,v) => (k, /* something that produces a new v */) }
myMap.mapValues(v => /* something that produces a new v */).view.force
Map() ++ myMap.mapValues(v => /* something that produces a new v */)如果您正在执行文件IO之类的操作来映射您的值(例如,如果您的值是文件名并映射到它们的内容),并且您不想一遍又一遍地读取该文件,那么这一点非常重要。
但是你的情况--你分配随机值--是另一个重要的例子,选择一个副本,而不是一遍又一遍地重新创建这些值。
https://stackoverflow.com/questions/5433578
复制相似问题