【问题标题】:Group matrix 9x9 elements into 3 row by 3 cols in Scala在Scala中将矩阵9x9元素分组为3行3列
【发布时间】:2013-02-28 14:37:14
【问题描述】:

假设我有以下矩阵:


val grid = Array(
  Array( 1, 2, 3,  4, 5, 6,  7, 8, 9), 
  Array(11,12,13, 14,15,16, 17,18,19), 
  Array(21,22,23, 24,25,26, 27,28,29), 

  Array(31,32,33, 34,35,36, 37,38,39), 
  Array(41,42,43, 44,45,46, 47,48,49), 
  Array(51,52,53, 54,55,56, 57,58,59), 

  Array(61,62,63, 64,65,66, 67,68,69), 
  Array(71,72,73, 74,75,76, 77,78,79), 
  Array(81,82,83, 84,85,86, 87,88,89)
)

我怎样才能,最好以函数的方式,将它们转换成这个矩阵:


val gridWithFields = Array(
  Array(1,2,3, 11,12,13, 21,22,23),
  Array(4,5,6, 14,15,16, 21,22,23),
  Array(7,8,9, 17,18,19, 27,28,29),
  ... 
)

*更新*
我做了一些基准测试,但不确定内存结果是否正确。无论如何,它们都在这里:

@maxmc for 的解决方案

周期中的 alg1:10 时间:2712683ns 内存:459572 周期中的 alg1:100 时间:914297ns 内存:458191 周期中的 alg1:1000 时间:85102ns 内存:457944 周期中的 alg1:10000 时间:68742ns 内存:457943

@Daniel C. Sobral 解决方案

周期中的 alg2:10 时间:3747031ns 内存:458889 循环中的 alg2:100 时间:1796564ns 内存:457951 循环中的 alg2:1000 时间:186215ns 内存:457220 循环中的 alg2:10000 时间:122642ns 内存:456708

@Or Peles 解决方案

周期中的 alg3:10 时间:741475ns 内存:457472 循环中的 alg3:100 时间:542181ns 内存:457914 循环中的 alg3:1000 时间:248020ns 内存:457911 循环中的 alg3:10000 时间:119105ns 内存:457919

@Hbf 解决方案

周期中的 alg4:10 时间:179093ns 内存:457472 循环中的 alg4:100 时间:121072ns 内存:457069 循环中的 alg4:1000 时间:78123ns 内存:456719 循环中的 alg4:10000 时间:75948ns 内存:455913

@Eastsun 解决方案

周期中的 alg5:10 时间:144037ns 内存:457512 循环中的 alg5:100 时间:40672ns 内存:457059 循环中的 alg5:1000 时间:42236ns 内存:456119 循环中的 alg5:10000 时间:46480ns 内存:455952

我已经在 MacMini(2012) 上对其进行了测试。内存结果真的很奇怪,所以来源在这里,如果有一些不好的错误和反模式请告诉我=)https://github.com/Stimphonier/MatrixBench

【问题讨论】:

  • 我想你的意思不是Array(4,5,6, 14,15,16, 21,22,23),而是Array(4,5,6, 14,15,16, 24,25,26),最后的...实际上应该是每个内部数组后面的三个...,对吧?
  • 如果您快速对各种建议的解决方案进行基准测试(时间,也许还有内存消耗)并报告结果,那就太好了。应该不会花很长时间,而且肯定会对社区有所帮助。
  • @mhs 我做了一些基准测试,但不确定结果是否正确
  • @Alexlv: 你应该把System.gc(); Thread.sleep(1000);System.gc(); Thread.sleep(1000) 放在time 方法的开头,以使内存结果更准确。

标签: scala matrix


【解决方案1】:

'for' 方法:

for(x <- 0 until 9 by 3) yield
  (for {
    row <- 0 until 9;
    col <- x until x + 3 by 3;
    i <- col until col + 3
  } yield grid(row)(i)).toArray   

【讨论】:

    【解决方案2】:

    分组和转置。我将展示我找出正确顺序的 REPL 会话。

    首先,您的数据中有一个分组——您用空格清楚地表明了这一点。每三行,每行内每三个元素。所以我们要做的第一件事就是明确分组。

    scala> grid.map(row => (row grouped 3).toArray)
    res7: Array[Array[Array[Int]]] = Array(Array(Array(1, 2, 3), Array(4, 5,
     6), Array(7, 8, 9)), Array(Array(11, 12, 13), Array(14, 15, 16), Array(
    17, 18, 19)), Array(Array(21, 22, 23), Array(24, 25, 26), Array(27, 28,
    29)), Array(Array(31, 32, 33), Array(34, 35, 36), Array(37, 38, 39)), Ar
    ray(Array(41, 42, 43), Array(44, 45, 46), Array(47, 48, 49)), Array(Arra
    y(51, 52, 53), Array(54, 55, 56), Array(57, 58, 59)), Array(Array(61, 62
    , 63), Array(64, 65, 66), Array(67, 68, 69)), Array(Array(71, 72, 73), A
    rray(74, 75, 76), Array(77, 78, 79)), Array(Array(81, 82, 83), Array(84,
     85, 86), Array(87, 88, 89)))
    
    scala> (res7 grouped 3).toArray
    res8: Array[Array[Array[Array[Int]]]] = Array(Array(Array(Array(1, 2, 3)
    , Array(4, 5, 6), Array(7, 8, 9)), Array(Array(11, 12, 13), Array(14, 15
    , 16), Array(17, 18, 19)), Array(Array(21, 22, 23), Array(24, 25, 26), A
    rray(27, 28, 29))), Array(Array(Array(31, 32, 33), Array(34, 35, 36), Ar
    ray(37, 38, 39)), Array(Array(41, 42, 43), Array(44, 45, 46), Array(47,
    48, 49)), Array(Array(51, 52, 53), Array(54, 55, 56), Array(57, 58, 59))
    ), Array(Array(Array(61, 62, 63), Array(64, 65, 66), Array(67, 68, 69)),
     Array(Array(71, 72, 73), Array(74, 75, 76), Array(77, 78, 79)), Array(A
    rray(81, 82, 83), Array(84, 85, 86), Array(87, 88, 89))))
    

    让我们看看我们是否正确:

    scala> res8(0)
    res9: Array[Array[Array[Int]]] = Array(Array(Array(1, 2, 3), Array(4, 5,
     6), Array(7, 8, 9)), Array(Array(11, 12, 13), Array(14, 15, 16), Array(
    17, 18, 19)), Array(Array(21, 22, 23), Array(24, 25, 26), Array(27, 28,
    29)))
    

    是的,这正是我们要转换的数据单元。让我们试试吧:

    scala> res9.transpose
    res10: Array[Array[Array[Int]]] = Array(Array(Array(1, 2, 3), Array(11,
    12, 13), Array(21, 22, 23)), Array(Array(4, 5, 6), Array(14, 15, 16), Ar
    ray(24, 25, 26)), Array(Array(7, 8, 9), Array(17, 18, 19), Array(27, 28,
     29)))
    

    如您所愿!所以让我们对整个矩阵进行操作:

    scala> res8 map (_.transpose)
    res11: Array[Array[Array[Array[Int]]]] = Array(Array(Array(Array(1, 2, 3
    ), Array(11, 12, 13), Array(21, 22, 23)), Array(Array(4, 5, 6), Array(14
    , 15, 16), Array(24, 25, 26)), Array(Array(7, 8, 9), Array(17, 18, 19),
    Array(27, 28, 29))), Array(Array(Array(31, 32, 33), Array(41, 42, 43), A
    rray(51, 52, 53)), Array(Array(34, 35, 36), Array(44, 45, 46), Array(54,
     55, 56)), Array(Array(37, 38, 39), Array(47, 48, 49), Array(57, 58, 59)
    )), Array(Array(Array(61, 62, 63), Array(71, 72, 73), Array(81, 82, 83))
    , Array(Array(64, 65, 66), Array(74, 75, 76), Array(84, 85, 86)), Array(
    Array(67, 68, 69), Array(77, 78, 79), Array(87, 88, 89))))
    

    现在我们只需要将其展平即可。我们需要以与分组相反的顺序将其展平:

    scala> res11.flatten
    res12: Array[Array[Array[Int]]] = Array(Array(Array(1, 2, 3), Array(11,
    12, 13), Array(21, 22, 23)), Array(Array(4, 5, 6), Array(14, 15, 16), Ar
    ray(24, 25, 26)), Array(Array(7, 8, 9), Array(17, 18, 19), Array(27, 28,
     29)), Array(Array(31, 32, 33), Array(41, 42, 43), Array(51, 52, 53)), A
    rray(Array(34, 35, 36), Array(44, 45, 46), Array(54, 55, 56)), Array(Arr
    ay(37, 38, 39), Array(47, 48, 49), Array(57, 58, 59)), Array(Array(61, 6
    2, 63), Array(71, 72, 73), Array(81, 82, 83)), Array(Array(64, 65, 66),
    Array(74, 75, 76), Array(84, 85, 86)), Array(Array(67, 68, 69), Array(77
    , 78, 79), Array(87, 88, 89)))
    
    scala> res12.map(_.flatten)
    res13: Array[Array[Int]] = Array(Array(1, 2, 3, 11, 12, 13, 21, 22, 23),
     Array(4, 5, 6, 14, 15, 16, 24, 25, 26), Array(7, 8, 9, 17, 18, 19, 27,
    28, 29), Array(31, 32, 33, 41, 42, 43, 51, 52, 53), Array(34, 35, 36, 44
    , 45, 46, 54, 55, 56), Array(37, 38, 39, 47, 48, 49, 57, 58, 59), Array(
    61, 62, 63, 71, 72, 73, 81, 82, 83), Array(64, 65, 66, 74, 75, 76, 84, 8
    5, 86), Array(67, 68, 69, 77, 78, 79, 87, 88, 89))
    

    或者,作为一个班轮:

    grid.map(_.grouped(3).toArray).grouped(3).toArray.map(_.transpose).flatten.map(_.flatten)
    

    【讨论】:

    • 谢谢你的解释,不知道转置方法=)
    【解决方案3】:
    val n: Array[Array[Int]] =
      grid.grouped(3)
          .toArray
          .flatMap(_.map(_.grouped(3).toArray)
                    .transpose
                    .map(_.flatten))
    
    n.foreach(r => {r.foreach(e => print(e + " ")); println})
    
    // 1 2 3 11 12 13 21 22 23 
    // 4 5 6 14 15 16 24 25 26 
    // 7 8 9 17 18 19 27 28 29 
    // 31 32 33 41 42 43 51 52 53 
    // 34 35 36 44 45 46 54 55 56 
    // 37 38 39 47 48 49 57 58 59 
    // 61 62 63 71 72 73 81 82 83 
    // 64 65 66 74 75 76 84 85 86 
    // 67 68 69 77 78 79 87 88 89
    

    应该可以通过将相应的implicit def 放入作用域来删除显式的toArray 调用。

    【讨论】:

      【解决方案4】:

      这是一个简短而有效的解决方案,可能是最短和最有效的解决方案:

      scala> val matrix = Array.tabulate(9, 9){ (r, c) => grid(r/3*3+c/3)(r%3*3+c%3) }
      matrix: Array[Array[Int]] = 
      Array(Array(1, 2, 3, 11, 12, 13, 21, 22, 23), 
            Array(4, 5, 6, 14, 15, 16, 24, 25, 26), 
            Array(7, 8, 9, 17, 18, 19, 27, 28, 29), 
            Array(31, 32, 33, 41, 42, 43, 51, 52, 53), 
            Array(34, 35, 36, 44, 45, 46, 54, 55, 56), 
            Array(37, 38, 39, 47, 48, 49, 57, 58, 59), 
            Array(61, 62, 63, 71, 72, 73, 81, 82, 83), 
            Array(64, 65, 66, 74, 75, 76, 84, 85, 86), 
            Array(67, 68, 69, 77, 78, 79, 87, 88, 89)
      )
      

      【讨论】:

      • 谢谢,非常喜欢您的解决方案
      【解决方案5】:

      这个怎么样?

      type Grid = Array[Array[Int]]
      
      def transform(grid: Grid): Grid = {
        def transformLine(grid: Grid) =
          grid.map(_.grouped(3).toArray).transpose.map(_.flatten)
        grid.grouped(3).flatMap(transformLine).toArray
      }
      
      scala> transform(grid) map(_.deep) foreach println
      Array(1, 2, 3, 11, 12, 13, 21, 22, 23)
      Array(4, 5, 6, 14, 15, 16, 24, 25, 26)
      Array(7, 8, 9, 17, 18, 19, 27, 28, 29)
      Array(31, 32, 33, 41, 42, 43, 51, 52, 53)
      Array(34, 35, 36, 44, 45, 46, 54, 55, 56)
      Array(37, 38, 39, 47, 48, 49, 57, 58, 59)
      Array(61, 62, 63, 71, 72, 73, 81, 82, 83)
      Array(64, 65, 66, 74, 75, 76, 84, 85, 86)
      Array(67, 68, 69, 77, 78, 79, 87, 88, 89)
      

      由于有很多隐式转换和中间结果,完全没有效率,但它是功能性的,除非你需要在一秒钟内执行数百次,否则应该不是问题......

      【讨论】:

        【解决方案6】:

        快速而肮脏(但实用)的破解:

        (0 until grid(0).size/3).toArray.
          map(i =>
            grid.flatMap(a => a.drop(i*3).take(3))
          )
        

        对于您提供的grid,这会产生:

        Array(
          Array(1, 2, 3, 11, 12, 13, 21, 22, 23, /*...*/, 71, 72, 73, 81, 82, 83),
          Array(4, 5, 6, 14, 15, 16, 24, 25, 26, /*...*/, 74, 75, 76, 84, 85, 86), 
          Array(7, 8, 9, 17, 18, 19, 27, 28, 29, /*...*/, 77, 78, 79, 87, 88, 89)
        )
        

        【讨论】:

          【解决方案7】:

          在一行中:

          grid.grouped(3).map(g => g.transpose.grouped(3).map(_.flatten.sorted)).flatten.toArray
          

          res25: Array[Array[Int]] = Array(Array(1, 2, 3, 11, 12, 13, 21, 22, 23), Array(4 , 5, 6, 14, 15, 16, 24, 25, 26), 数组(7, 8, 9, 17, 18, 19, 27, 28, 29), 数组(3 1, 32, 33, 41, 42, 43, 51, 52, 53), 数组(34, 35, 36, 44, 45, 46, 54, 55, 56), A 阵列(37, 38, 39, 47, 48, 49, 57, 58, 59),阵列(61, 62, 63, 71, 72, 73, 81, 82, 83), 数组(64, 65, 66, 74, 75, 76, 84, 85, 86), 数组(67, 68, 69, 77, 78, 79, 87 , 88, 89))

          【讨论】:

            猜你喜欢
            • 2018-05-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-11-27
            • 1970-01-01
            • 1970-01-01
            • 2012-06-22
            • 2017-04-25
            相关资源
            最近更新 更多