声明类型不同时的不同行为(Set 与 TreeSet)

发布于 2024-10-09 10:27:56 字数 821 浏览 2 评论 0原文

    var set = TreeSet(5,4,3,2,1)
    println(set)

    val diffSet: TreeSet[Int] = set
    // if I change above code to val diffSet: Set[Int] = set
    // the result is unsorted set.

    for (i <- diffSet; x = i) {
        println(i)
    }
    println("-" * 20)
    // the above code translates to below and print the same result
    val temp = diffSet.map(i => (i, i))
    for ((i, x) <- temp) {
        println(i)
    }

我的问题是,如果我定义了这样的方法:

def genSet:Set[Int] = {
  TreeSet(5, 4, 3, 2, 1)
}

当我想使用 for 循环时,

for (i <- genSet; x = i + 1) {
  println(x)
}

结果是未排序的,如何在不更改 genSet 的返回类型的情况下修复此行为。如果我像下面这样使用for循环,那就没问题了,但我希望保留上面的代码风格。

for (i <- genSet) {
  val x = i + 1
  println(x)
}
    var set = TreeSet(5,4,3,2,1)
    println(set)

    val diffSet: TreeSet[Int] = set
    // if I change above code to val diffSet: Set[Int] = set
    // the result is unsorted set.

    for (i <- diffSet; x = i) {
        println(i)
    }
    println("-" * 20)
    // the above code translates to below and print the same result
    val temp = diffSet.map(i => (i, i))
    for ((i, x) <- temp) {
        println(i)
    }

My question is if I defined a method like this:

def genSet:Set[Int] = {
  TreeSet(5, 4, 3, 2, 1)
}

and when i want to use a for loop with it

for (i <- genSet; x = i + 1) {
  println(x)
}

the result is unsorted, how to fix this behavior without change the genSet's return type. if I use for loop like below, it will be fine, but I hope to keep the above code style.

for (i <- genSet) {
  val x = i + 1
  println(x)
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

苏璃陌 2024-10-16 10:27:56

为什么 map 版本最终未排序

map 方法(使用我们将调用 func 的函数调用)采用隐式 CanBuildFrom 参数,除了考虑 func 返回的类型以选择适当的返回类型之外,还考虑调用 map 的集合类型。这用于使 Map.map[Int]BitSet.map[String] 做正确的事情(返回通用列表),而 Map.map[ (String,Int)]BitSet.map[Int] 也做正确的事情(返回一个 Map 和一个 BitSet ) 分别。

CanBuildFrom 是在编译时选择的,因此必须根据您调用 map 的集合的静态类型(类型编译器在编译时就知道)。 set 的静态类型是 TreeSet,但 diffset 的静态类型是 Set。两者(运行时)的动态类型都是TreeSet

当您在 setTreeSet)上调用 map 时,编译器会选择 immutable.this.SortedSet.canBuildFrom[Int](math .this.Ordering.Int) 作为 CanBuildFrom

当您在 diffsetSet)上调用 map 时,编译器会选择 immutable.this.Set.canBuildFrom[Int] 作为 CanBuildFrom

为什么 for 版本最终未排序

循环脱

for (i <- genSet; x = i + 1) {
  println(x)
}

糖为

genSet.map(((i) => {
              val x = i.$plus(1);
              scala.Tuple2(i, x)
            })).foreach(((x$1) => x$1: @scala.unchecked match {
              case scala.Tuple2((i @ _), (x @ _)) => println(x)
            }))

脱糖版本包含一个 map 函数,该函数将使用未排序的 CanBuildFrom,正如我上面所解释的。

另一方面,循环

for (i <- genSet) {
  val x = i + 1
  println(x)
}

脱糖到

genSet.foreach(((i) => {
              val x = i.$plus(1);
              println(x)
            }))

Which 根本不使用 CanBuildFrom,因为没有返回新的集合。

Why the map version winds up unsorted

The map method (called with a function that we'll call func) takes an implicit CanBuildFrom parameter that takes into account the type of the collection that map is being called on, in addition to the type that func returns to choose an appropriate return type. This is used to make Map.map[Int] or BitSet.map[String] do the right thing (return general purpose lists) while Map.map[(String,Int)] or BitSet.map[Int] also do the right thing (return a Map and a BitSet) respectively.

The CanBuildFrom is chosen at compile time, so it must be chosen based on the static type of the set that you call map on (the type the compiler knows about at compile time). The static type of set is TreeSet, but the static type of diffset is Set. The dynamic type of both (at runtime) is TreeSet.

When you call map on set (a TreeSet), the compiler chooses immutable.this.SortedSet.canBuildFrom[Int](math.this.Ordering.Int) as the CanBuildFrom.

When you call map on diffset (a Set), the compiler chooses immutable.this.Set.canBuildFrom[Int] as the CanBuildFrom.

Why the for version winds up unsorted

The loop

for (i <- genSet; x = i + 1) {
  println(x)
}

desugars into

genSet.map(((i) => {
              val x = i.$plus(1);
              scala.Tuple2(i, x)
            })).foreach(((x$1) => x$1: @scala.unchecked match {
              case scala.Tuple2((i @ _), (x @ _)) => println(x)
            }))

The desugared version includes a map function which will use the unsorted CanBuildFrom as I explained above.

On the other hand, the loop

for (i <- genSet) {
  val x = i + 1
  println(x)
}

desugars into

genSet.foreach(((i) => {
              val x = i.$plus(1);
              println(x)
            }))

Which doesn't use a CanBuildFrom at all, since no new collection is being returned.

小情绪 2024-10-16 10:27:56

Set 不保证顺序。即使底层类是 TreeSet,如果预期结果是 Set,您也会在第一次转换时失去顺序。

如果您想要排序,请不要使用Set。我建议使用 SortedSet

Set does not guarantee ordering. Even if the underlying class is a TreeSet, if the expected result is a Set you'll loose the ordering in the first transformation you do.

If you want ordering, do not use Set. I suggest, say, SortedSet.

猫瑾少女 2024-10-16 10:27:56

更改 genSet 的 sig 以返回 SortedSet

def genSet:SortedSet[Int] = {
  TreeSet(5, 4, 3, 2, 1)
}

这可能是某种错误。我本来希望你的代码也能工作。

我认为 map 是罪魁祸首。这会导致相同的行为:

for (i <- genSet.map(_ + 1)) { println(i) }

并且 for(i <- genSet; x = i + 1) 等于 for(x <- genSet.map({i => i + 1}))

Change the sig of genSet to return a SortedSet

def genSet:SortedSet[Int] = {
  TreeSet(5, 4, 3, 2, 1)
}

This is probably some sort of bug. I would have expected your code to work too.

I think map is the culprit. This results in the same behavior:

for (i <- genSet.map(_ + 1)) { println(i) }

And for(i <- genSet; x = i + 1) equates to for(x <- genSet.map({i => i + 1}))

一世旳自豪 2024-10-16 10:27:56

你可以这样做:

scala> for (i <-genSet.view; x = i + 1) println(x)
2
3
4
5
6

虽然,这是一种技巧,当你几个月后查看它时,你可能想知道为什么添加 .view ...

You can do:

scala> for (i <-genSet.view; x = i + 1) println(x)
2
3
4
5
6

Although, it's the type of trick that when you look at it after a few months, you may wonder why you added .view ...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文