在二维数组中找到“列式”最大值

时间:2016-03-30 13:08:55

标签: arrays scala

假设我有一个二维数组,例如:

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)其他一些改进方法?

2 个答案:

答案 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你不想在内存中存储中间结果(即排序,然后转置),那么你的想法肯定是要走的路。如果您的矩阵在磁盘上,您甚至不需要加载它,您可以只在行上迭代一次