假设我有一个二维数组,例如:
val A1 = Array(Array(4,0,0,0),Array(3),Array(3,4,40,1),Array(50,2))
现在我希望每个位置都有最多的项目。
如果我以矩阵形式编写上面的数组,那么很明显我的意思是“列式”最大值:
4 0 0 0
3
3 4 40 1
50 2
----------
50 4 40 1 (result)
所以这个案例的答案是Array(50,4,40,1)
(空值会被忽略)。
我可以这样做:
A1.foldLeft(A1.head)( (x1, x2) =>
x1.padTo(x2.length, Int.MinValue).zip(x2.padTo(x1.length,Int.MinValue)).
map { pair => pair._1 max pair._2 }
)
但不知何故,这对于像这样的简单事情来说感觉非常硬。所以我希望有一种更简单的方法来做到这一点。
也许有
1)有些功能直接这样做吗?
2)有一种方法可以“使用默认值压缩”:x1.padTo(x2.length, Int.MinValue).zip(x2.padTo(x1.length,Int.MinValue))
更好吗?
3)其他一些改进方法?
答案 0 :(得分:6)
使用.tranpose
获取'列'在Array[Array[Int]]
中,然后拨打.map(_.max)
以获取所有这些内容的最大值:
scala> val A1 = Array(Array(4,0,0,0),Array(3),Array(3,4,40,1),Array(50,2))
A1: Array[Array[Int]] = Array(Array(4, 0, 0, 0), Array(3), Array(3, 4, 40, 1), Array(50, 2))
scala> A1.transpose
res5: Array[Array[Int]] = Array(Array(4, 3, 3, 50), Array(0, 4, 2), Array(0, 40), Array(0, 1))
scala> A1.transpose.map(_.max)
res6: Array[Int] = Array(50, 4, 40, 1)
修改强>:
如果.tranpose
中稍后遇到的Array
比第一个Array[Array[T]]
更长,scala> Array(Array(1,2,3), Array(1,2,3,4)).transpose
java.lang.ArrayIndexOutOfBoundsException: 3
at scala.collection.mutable.ArrayOps$$anonfun$transpose$1$$anonfun$apply$1.apply(ArrayOps.scala:102)
at scala.collection.mutable.ArrayOps$$anonfun$transpose$1$$anonfun$apply$1.apply(ArrayOps.scala:101)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
at scala.collection.mutable.ArrayOps$ofInt.foreach(ArrayOps.scala:234)
at scala.collection.mutable.ArrayOps$$anonfun$transpose$1.apply(ArrayOps.scala:101)
at scala.collection.mutable.ArrayOps$$anonfun$transpose$1.apply(ArrayOps.scala:99)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:186)
at scala.collection.mutable.ArrayOps$class.transpose(ArrayOps.scala:99)
at scala.collection.mutable.ArrayOps$ofRef.transpose(ArrayOps.scala:186)
... 32 elided
scala> Array(Array(1,2,3,4), Array(1,2,3)).transpose
res5: Array[Array[Int]] = Array(Array(1, 1), Array(2, 2), Array(3, 3), Array(4))
可能会引发异常:
scala> Array(Array(1,2,3), Array(1,2,3,4)).sortBy(-_.length).transpose
res6: Array[Array[Int]] = Array(Array(1, 1), Array(2, 2), Array(3, 3), Array(4))
如果在您的情况下可能发生这种情况,您可以始终按内部数组长度(按降序排序)对外部数组进行排序:
CM:
答案 1 :(得分:3)
transpose
答案是正确的。为了完整起见,存在zipAll
函数。 fold + zip版本如下所示:
A1.reduceLeft((x1, x2) =>
x1.zipAll(x2, Int.MinValue, Int.MinValue)
.map { case (x, y) => x max y }
)
你可以轻松编写一个并行版本,因为max是一个可交换的monoid,你可以使用reduce
(不是左或右)
A1.par.reduce((x1, x2) =>
x1.zipAll(x2, Int.MinValue, Int.MinValue)
.map { case (x, y) => x max y }
)
你走在正确的轨道上,这个版本肯定更快,使用的内存比用于大型数组的排序+转置少得多,例如。
val A1 = Array.fill(100000)(Array.fill(Random.nextInt(100000))(Random.nextInt()))
如果你只需要计算一个max
你不想在内存中存储中间结果(即排序,然后转置),那么你的想法肯定是要走的路。如果您的矩阵在磁盘上,您甚至不需要加载它,您可以只在行上迭代一次