首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >subsetOf与forall包含

subsetOf与forall包含
EN

Stack Overflow用户
提问于 2011-03-25 14:10:10
回答 1查看 818关注 0票数 3

考虑到我有:

代码语言:javascript
复制
case class X(...)
val xs: Seq[X] = ... // some method result
val ys: Seq[X] = ... // some other method result

下列情况成立:

代码语言:javascript
复制
xs.distinct.sameElements(xs) // true
ys.distinct.sameElements(ys) // true

我要面对的是:

代码语言:javascript
复制
xs forall(ys contains _)    // true
xs.toSet subsetOf ys.toSet  // false

为什么?我的意思是,很明显,在重复的情况下,从SetSeq中选择随机元素,但是因为"(...).distinct.sameElements(...)“而没有重复元素。

我当然需要更深入的了解这种平等检查.

编辑:

经过长时间的搜索,我发现了这个问题,并将其浓缩如下:

我的元素不一样,但是我必须仔细看看为什么distinct.sameElements没有抱怨。但与此同时,又出现了一个新问题:

考虑到这一点:

代码语言:javascript
复制
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不同,尽管两者都是不可变的映射。这对我来说不是直觉上的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2011-03-26 12:09:12

造成这一领域问题的最常见的原因是测试集相等之类的。

  1. hashCode不符合equals
  2. Your值是不稳定的(因此以前的hashCode不符合当前的equals)

原因是这很重要,因为distincttoSet使用哈希代码构建集合,而contains只是使用exists运行集合。

代码语言:javascript
复制
xs forall(ys contains _) == xs forall (x => ys exists (y => x==y) )

这变得更加复杂,因为许多集合直到它们大于最小大小(通常是4)时才开始使用散列代码,所以在测试中并不总是注意到这一点。但让我们证明给自己看:

代码语言:javascript
复制
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!

好的,现在我们知道,对大多数这些操作来说,匹配hashCodeequals是一件好事。

警告:在Java中,即使是原语也经常发生不匹配:

代码语言:javascript
复制
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现在至少捕捉到了这一点(希望每次都这样):

代码语言:javascript
复制
(new java.lang.Float(1.0)).## == (new java.lang.Integer(1)).##   // Whew

Case类也正确地完成了这一任务,因此我们有三种可能

  1. ,您超越了equals,而不是hashCode来匹配
  2. ,您的值不稳定,
  3. 有一个bug,并且Java包装的原始hashCode错配会回来咬你

G 229

第一个很简单。

第二个问题似乎是您的问题,这是因为mapValues实际上创建了原始集合的视图,而不是新的集合。(filterKeys也会这样做。)就我个人而言,我认为这是一个有问题的设计选择,因为通常当你有一个视图,你想要做一个单一的具体实例,你.force它。但是默认映射没有.force,因为它们没有意识到它们可能是视图。所以你不得不求助于

代码语言:javascript
复制
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之类的操作来映射您的值(例如,如果您的值是文件名并映射到它们的内容),并且您不想一遍又一遍地读取该文件,那么这一点非常重要。

但是你的情况--你分配随机值--是另一个重要的例子,选择一个副本,而不是一遍又一遍地重新创建这些值。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5433578

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档