Scala 集合:完全不可预测的行为

发布于 2024-09-10 12:13:10 字数 4063 浏览 8 评论 0原文

对 Scala 2.8 的收集行为感到非常沮丧。问题是:我正在创建一个数独板。我正在标记从 A1 到 I9 的单元格(字母是行,数字是列)。我想获得棋盘上的单位列表,即9行、夜间列和夜间象限。

这是我的 scala 类:

class Square(val row:Char, val column:Int) extends Pair[Char, Int](row, column) {
    override def toString() = "" + row + column 
}

object Board {
    private val rows = "ABCDEFGHI"
    private val cols = 1 to 9
    private lazy val units = unitList(rows, cols)
    private def cross(rows:Iterable[Char], columns:Iterable[Int]):Iterable[Square] = {
        for (row <- rows; col <- columns)
            yield new Square(row, col)
    }

    private def unitList(rows:Iterable[Char], cols:Iterable[Int]) = {
        val u1 = (for (col <- cols) yield cross(rows, List(col)))
        val u2 = (for (row <- rows) yield cross(List(row), cols))
        val u3 = (for (cols <- List("ABC", "DEF", "GHI"); rows <- List(1 to 3, 4 to 6, 7 to 9)) yield cross(cols, rows))

        u1 :+ u2 :+ u3  // won't compile, reason: :+ is not a member of Iterable[Iterable[sudoku.Square]]
    }

    def run() {
        val u1 = (for (col <- cols) yield cross(rows, List(col)))
        val u2 = (for (row <- rows) yield cross(List(row), cols))
        val u3 = (for (cols <- List("ABC", "DEF", "GHI"); rows <- List(1 to 3, 4 to 6, 7 to 9)) yield cross(cols, rows))
        println(u1)
        println(u2)
        println(u3)
        val u4 = u1 :+ u2 :+ u3  // compiles
        println(u1 :+ u2 :+ u3)  // compiles and output correctly
    }
}

请参阅代码中的注释。具体来说,为什么相同的代码不会在unitList中编译,但在run()中编译并运行良好?

另外,当我观察 run 方法的输出时,yield 关键字返回的集合似乎在 Vector 和 List 之间随机切换:

Vector(Vector(A1, B1, C1, D1, E1, F1, G1, H1, I1), Vector(A2, B2, C2, D2, E2, F2, G2, H2, I2), Vector(A3, B3, C3, D3, E3, F3, G3, H3, I3), Vector(A4, B4, C4, D4, E4, F4, G4, H4, I4), Vector(A5, B5, C5, D5, E5, F5, G5, H5, I5), Vector(A6, B6, C6, D6, E6, F6, G6, H6, I6), Vector(A7, B7, C7, D7, E7, F7, G7, H7, I7), Vector(A8, B8, C8, D8, E8, F8, G8, H8, I8), Vector(A9, B9, C9, D9, E9, F9, G9, H9, I9))

Vector(List(A1, A2, A3, A4, A5, A6, A7, A8, A9), List(B1, B2, B3, B4, B5, B6, B7, B8, B9), List(C1, C2, C3, C4, C5, C6, C7, C8, C9), List(D1, D2, D3, D4, D5, D6, D7, D8, D9), List(E1, E2, E3, E4, E5, E6, E7, E8, E9), List(F1, F2, F3, F4, F5, F6, F7, F8, F9), List(G1, G2, G3, G4, G5, G6, G7, G8, G9), List(H1, H2, H3, H4, H5, H6, H7, H8, H9), List(I1, I2, I3, I4, I5, I6, I7, I8, I9))

List(Vector(A1, A2, A3, B1, B2, B3, C1, C2, C3), Vector(A4, A5, A6, B4, B5, B6, C4, C5, C6), Vector(A7, A8, A9, B7, B8, B9, C7, C8, C9), Vector(D1, D2, D3, E1, E2, E3, F1, F2, F3), Vector(D4, D5, D6, E4, E5, E6, F4, F5, F6), Vector(D7, D8, D9, E7, E8, E9, F7, F8, F9), Vector(G1, G2, G3, H1, H2, H3, I1, I2, I3), Vector(G4, G5, G6, H4, H5, H6, I4, I5, I6), Vector(G7, G8, G9, H7, H8, H9, I7, I8, I9))

Vector(Vector(A1, B1, C1, D1, E1, F1, G1, H1, I1), Vector(A2, B2, C2, D2, E2, F2, G2, H2, I2), Vector(A3, B3, C3, D3, E3, F3, G3, H3, I3), Vector(A4, B4, C4, D4, E4, F4, G4, H4, I4), Vector(A5, B5, C5, D5, E5, F5, G5, H5, I5), Vector(A6, B6, C6, D6, E6, F6, G6, H6, I6), Vector(A7, B7, C7, D7, E7, F7, G7, H7, I7), Vector(A8, B8, C8, D8, E8, F8, G8, H8, I8), Vector(A9, B9, C9, D9, E9, F9, G9, H9, I9), Vector(List(A1, A2, A3, A4, A5, A6, A7, A8, A9), List(B1, B2, B3, B4, B5, B6, B7, B8, B9), List(C1, C2, C3, C4, C5, C6, C7, C8, C9), List(D1, D2, D3, D4, D5, D6, D7, D8, D9), List(E1, E2, E3, E4, E5, E6, E7, E8, E9), List(F1, F2, F3, F4, F5, F6, F7, F8, F9), List(G1, G2, G3, G4, G5, G6, G7, G8, G9), List(H1, H2, H3, H4, H5, H6, H7, H8, H9), List(I1, I2, I3, I4, I5, I6, I7, I8, I9)), List(Vector(A1, A2, A3, B1, B2, B3, C1, C2, C3), Vector(A4, A5, A6, B4, B5, B6, C4, C5, C6), Vector(A7, A8, A9, B7, B8, B9, C7, C8, C9), Vector(D1, D2, D3, E1, E2, E3, F1, F2, F3), Vector(D4, D5, D6, E4, E5, E6, F4, F5, F6), Vector(D7, D8, D9, E7, E8, E9, F7, F8, F9), Vector(G1, G2, G3, H1, H2, H3, I1, I2, I3), Vector(G4, G5, G6, H4, H5, H6, I4, I5, I6), Vector(G7, G8, G9, H7, H8, H9, I7, I8, I9)))

我在这里完全迷失了。

Have been pretty frustrated by Scala 2.8 collection behaviours. Here's the problem: I'm creating a Sudoku board. I'm labelling the cells from A1 to I9 (the letters being the rows and the digits being the columns). I want to get a list of units on the board, which is the 9 rows, the night columns, and the night quadrants.

Here's my scala class:

class Square(val row:Char, val column:Int) extends Pair[Char, Int](row, column) {
    override def toString() = "" + row + column 
}

object Board {
    private val rows = "ABCDEFGHI"
    private val cols = 1 to 9
    private lazy val units = unitList(rows, cols)
    private def cross(rows:Iterable[Char], columns:Iterable[Int]):Iterable[Square] = {
        for (row <- rows; col <- columns)
            yield new Square(row, col)
    }

    private def unitList(rows:Iterable[Char], cols:Iterable[Int]) = {
        val u1 = (for (col <- cols) yield cross(rows, List(col)))
        val u2 = (for (row <- rows) yield cross(List(row), cols))
        val u3 = (for (cols <- List("ABC", "DEF", "GHI"); rows <- List(1 to 3, 4 to 6, 7 to 9)) yield cross(cols, rows))

        u1 :+ u2 :+ u3  // won't compile, reason: :+ is not a member of Iterable[Iterable[sudoku.Square]]
    }

    def run() {
        val u1 = (for (col <- cols) yield cross(rows, List(col)))
        val u2 = (for (row <- rows) yield cross(List(row), cols))
        val u3 = (for (cols <- List("ABC", "DEF", "GHI"); rows <- List(1 to 3, 4 to 6, 7 to 9)) yield cross(cols, rows))
        println(u1)
        println(u2)
        println(u3)
        val u4 = u1 :+ u2 :+ u3  // compiles
        println(u1 :+ u2 :+ u3)  // compiles and output correctly
    }
}

See the comments in the code. Specifically, why the same code won't compile in unitList but compiles and runs fine in run()?

Also, when I observe the output of the run method, it seems the collection returned by the yield keyword is randomly switching between Vector and List:

Vector(Vector(A1, B1, C1, D1, E1, F1, G1, H1, I1), Vector(A2, B2, C2, D2, E2, F2, G2, H2, I2), Vector(A3, B3, C3, D3, E3, F3, G3, H3, I3), Vector(A4, B4, C4, D4, E4, F4, G4, H4, I4), Vector(A5, B5, C5, D5, E5, F5, G5, H5, I5), Vector(A6, B6, C6, D6, E6, F6, G6, H6, I6), Vector(A7, B7, C7, D7, E7, F7, G7, H7, I7), Vector(A8, B8, C8, D8, E8, F8, G8, H8, I8), Vector(A9, B9, C9, D9, E9, F9, G9, H9, I9))

Vector(List(A1, A2, A3, A4, A5, A6, A7, A8, A9), List(B1, B2, B3, B4, B5, B6, B7, B8, B9), List(C1, C2, C3, C4, C5, C6, C7, C8, C9), List(D1, D2, D3, D4, D5, D6, D7, D8, D9), List(E1, E2, E3, E4, E5, E6, E7, E8, E9), List(F1, F2, F3, F4, F5, F6, F7, F8, F9), List(G1, G2, G3, G4, G5, G6, G7, G8, G9), List(H1, H2, H3, H4, H5, H6, H7, H8, H9), List(I1, I2, I3, I4, I5, I6, I7, I8, I9))

List(Vector(A1, A2, A3, B1, B2, B3, C1, C2, C3), Vector(A4, A5, A6, B4, B5, B6, C4, C5, C6), Vector(A7, A8, A9, B7, B8, B9, C7, C8, C9), Vector(D1, D2, D3, E1, E2, E3, F1, F2, F3), Vector(D4, D5, D6, E4, E5, E6, F4, F5, F6), Vector(D7, D8, D9, E7, E8, E9, F7, F8, F9), Vector(G1, G2, G3, H1, H2, H3, I1, I2, I3), Vector(G4, G5, G6, H4, H5, H6, I4, I5, I6), Vector(G7, G8, G9, H7, H8, H9, I7, I8, I9))

Vector(Vector(A1, B1, C1, D1, E1, F1, G1, H1, I1), Vector(A2, B2, C2, D2, E2, F2, G2, H2, I2), Vector(A3, B3, C3, D3, E3, F3, G3, H3, I3), Vector(A4, B4, C4, D4, E4, F4, G4, H4, I4), Vector(A5, B5, C5, D5, E5, F5, G5, H5, I5), Vector(A6, B6, C6, D6, E6, F6, G6, H6, I6), Vector(A7, B7, C7, D7, E7, F7, G7, H7, I7), Vector(A8, B8, C8, D8, E8, F8, G8, H8, I8), Vector(A9, B9, C9, D9, E9, F9, G9, H9, I9), Vector(List(A1, A2, A3, A4, A5, A6, A7, A8, A9), List(B1, B2, B3, B4, B5, B6, B7, B8, B9), List(C1, C2, C3, C4, C5, C6, C7, C8, C9), List(D1, D2, D3, D4, D5, D6, D7, D8, D9), List(E1, E2, E3, E4, E5, E6, E7, E8, E9), List(F1, F2, F3, F4, F5, F6, F7, F8, F9), List(G1, G2, G3, G4, G5, G6, G7, G8, G9), List(H1, H2, H3, H4, H5, H6, H7, H8, H9), List(I1, I2, I3, I4, I5, I6, I7, I8, I9)), List(Vector(A1, A2, A3, B1, B2, B3, C1, C2, C3), Vector(A4, A5, A6, B4, B5, B6, C4, C5, C6), Vector(A7, A8, A9, B7, B8, B9, C7, C8, C9), Vector(D1, D2, D3, E1, E2, E3, F1, F2, F3), Vector(D4, D5, D6, E4, E5, E6, F4, F5, F6), Vector(D7, D8, D9, E7, E8, E9, F7, F8, F9), Vector(G1, G2, G3, H1, H2, H3, I1, I2, I3), Vector(G4, G5, G6, H4, H5, H6, I4, I5, I6), Vector(G7, G8, G9, H7, H8, H9, I7, I8, I9)))

I'm totally at lost here.

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

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

发布评论

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

评论(3

请帮我爱他 2024-09-17 12:13:10

for 理解中的产量结果是从第一个生成器的类型派生的,在您的方法中,您限制了参数的类型,到目前为止您丢失了 :+ 方法。

//The type of 1 to 9 is show below
scala> 1 to 9
res0: scala.collection.immutable.Range.Inclusive with scala.collection.immutable.Range.ByOne = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)


//If you cast it to Iterable[Int] it doens't have the :+ method
scala> (res0:Iterable[Int]) :+ 1
<console>:7: error: value :+ is not a member of Iterable[Int]
       (res0:Iterable[Int]) :+ 1
       ^

//But if you don't, you have it
scala> res0 :+ 1                
res6: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 1)

//And to prove that for comprehensions yield derives the type of the first generator:

scala> for(a <- res0) yield a
res7: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9)

scala> for(a <- (res0:Iterable[Int])) yield a
res8: Iterable[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9)

The result of the yield in the for comprehension is derived from the type of the first generator, in you method, you're constraining the types of your parameters so far you lose your :+ methods.

//The type of 1 to 9 is show below
scala> 1 to 9
res0: scala.collection.immutable.Range.Inclusive with scala.collection.immutable.Range.ByOne = Range(1, 2, 3, 4, 5, 6, 7, 8, 9)


//If you cast it to Iterable[Int] it doens't have the :+ method
scala> (res0:Iterable[Int]) :+ 1
<console>:7: error: value :+ is not a member of Iterable[Int]
       (res0:Iterable[Int]) :+ 1
       ^

//But if you don't, you have it
scala> res0 :+ 1                
res6: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 1)

//And to prove that for comprehensions yield derives the type of the first generator:

scala> for(a <- res0) yield a
res7: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9)

scala> for(a <- (res0:Iterable[Int])) yield a
res8: Iterable[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9)
吝吻 2024-09-17 12:13:10

尽管行为确实很奇怪,但 :+ 不可能是您想要的运算符。由于您没有注释 unitList 的返回类型,我不知道您期望什么。我假设您想要返回 Iterable[Square]Iterable[Iterable[Square]]。那么让我们看看如何获​​取它们,以及为什么 :+ 不正确。

首先,u1u2u3都是Iterable[Iterable[Square]],尽管确切的亚型各异。这应该很容易理解:cross 返回 Iterable[Square],因此在 for 理解中产生 cross 会产生 Iterable [可迭代[方形]]

接下来,让我们考虑 :+。此方法向集合添加一个元素,因此,如果 u1Iterable(a, b, c),其中 a、b 和 c 是 Iterable[Square ],则 u1 :+ u2Iterable(a, b, c, u2),其类型变为 Iterable[X] code>,其中 XIterable[Square](a、b 和 c 的类型)和 Iterable[Iterable[Square]] 的统一code>(u2 的类型)。最终结果是一个Iterable[Iterable[AnyRef]]

由于 u1u2u3 的类型本质上是相同的,因此正确的操作很可能是这样的:

u1 ++ u2 ++ u3

它将返回 可迭代[可迭代[方形]]。现在,如果您想删除嵌套并返回 Iterable[Square],您可以将其展平:

(u1 ++ u2 ++ u3).flatten

这两件事之一可能就是您想要的。

现在,至于“随机”切换,没有什么随机的。在每种情况下,都有两个 for 推导式,并且结果集合的实际实现取决于原始集合的实现。因此,让我们考虑一下:

  • u1:外部类型源自 Range,内部类型源自 String(要交叉的第一个参数)
  • u2:外部类型源自 String code>,内部类型来自 List(要交叉的第一个参数)
  • u3:外部类型源自 List,内部类型源自 String(第一个参数 <

因此可以很容易地推断出对 String (实际上是 WrappedString)和 Range 的 for 理解会产生 Vector /code>,而对 List 的 for 推导则生成 List

Notwithstanding the really weird behavior, :+ cannot possibly be the operator you want. Since you did not annotate the return type of unitList, I don't know what you expected. I assume you wanted to return either Iterable[Square] or Iterable[Iterable[Square]]. So let's see how you can get them, and why :+ is incorrect.

First of all, u1, u2 and u3 are all Iterable[Iterable[Square]], though the exact subtype varies. This should be easy to understand: cross returns Iterable[Square], so yielding cross in a for-comprehension results in an Iterable[Iterable[Square]].

Next, Let's consider :+. This method adds an element to a collection, so, if u1 is Iterable(a, b, c), where a, b and c are Iterable[Square], then u1 :+ u2 is Iterable(a, b, c, u2), and its type becomes Iterable[X], where X is the unification of Iterable[Square] (the type of a, b and c) and Iterable[Iterable[Square]] (the type of u2). The end result is an Iterable[Iterable[AnyRef]].

Since the type of u1, u2 and u3 are essentially the same, the correct operation in all likelyhood is this:

u1 ++ u2 ++ u3

Which will return Iterable[Iterable[Square]]. Now, if you want to remove the nesting and return Iterable[Square], you can flatten this:

(u1 ++ u2 ++ u3).flatten

One of these two things is probably what you want.

Now, as for the "random" switching, there's nothing random about it. In each case, there are two for-comprehensions, and the actual implementation of the resulting collection depends on the implementation of the original collection. So, let's consider it:

  • u1: outer type derives from Range, inner type from String (first parameter to cross)
  • u2: outer type derives from String, inner type from List (first parameter to cross)
  • u3: outer type derives from List, inner type derives from String (first parameter to cross)

So it can be easily deduced that for-comprehensions over String (WrappedString, actually) and Range result in Vector, while for-comprehensions over List result in List.

苦行僧 2024-09-17 12:13:10

发生编译器错误是因为 :+IndexedSeq 的成员(因此也是 List)的成员,但不是 Iterable 的成员。如果将 unitList 的返回值更改为 ,

u1 :+ u2 :+ u3

它就

List(u1) :+ u2 :+ u3

可以正常编译。

The compiler error occurs because :+ is a member of IndexedSeq (and thus List) but not of Iterable. If you change the return value of unitList from

u1 :+ u2 :+ u3

to

List(u1) :+ u2 :+ u3

it compiles just fine.

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