[英]Scala logical indexing with for comprehension
我正在嘗試將以下Matlab邏輯索引模式轉換為Scala代碼:
% x is an [Nx1] array of Int32
% y is an [Nx1] array of Int32
% myExpensiveFunction() processes batches of unique x.
ux = unique(x);
z = nan(size(x));
for i = 1:length(ux)
idx = x == ux(i);
z(idx) = myExpensiveFuntion(x(idx), y(idx));
end
假設我在Scala中使用val x: Array[Int]
。 做這個的最好方式是什么?
編輯:為澄清起見,我正在一次處理按唯一x分組的(x,y)批處理,並返回具有與初始輸入相對應的順序的結果(z)。 我可以對x進行排序,但最終需要回到原始的未排序順序。 我的主要要求是以清晰有效的方式處理所有索引/映射/排序。
在Scala中,大多數操作都非常簡單。 唯一與眾不同的是唯一的x
索引。 在Scala中,您可以使用`groupBy'。 由於這是一種非常繁重的索引方法,因此我將一路讓步並使用索引:
val z = Array.fill(x.length)(Double.NaN)
x.indices.groupBy(i => x(i)).foreach{ case (xi, is) =>
is.foreach(i => z(i) = myExpensiveFunction(xi, y(i)))
}
z
假設您可以缺少前往myExpensiveFunction
的向量。 如果不,
val z = Array.fill(x.length)(Double.NaN)
x.indices.groupBy(i => x(i)).foreach{ case (xi, is) =>
val xs = Array.fill(is.length)(xi)
val ys = is.map(i => y(i)).toArray
val zs = myExpensiveFunction(xs, ys)
is.foreach(i => z(i) = zs(i))
}
z
這不是在Scala中進行計算的最自然的方法,也不是最有效的,但是如果您的昂貴函數昂貴,您就不會在乎效率,這是我可以最直接進行直譯的地方。
(將您的matlab算法轉換成幾乎所有其他內容都需要一定的痛苦或重新思考,因為matlab中的“自然”計算不同於大多數其他語言中的計算。)
重要的是要獲得Matlab的unique
權利。 一個簡單的解決方案是使用Set
來確定唯一值:
val occurringValues = x.toSet
occurringValues.foreach{ value =>
val indices = x.indices.filter(i => x(i) == value)
for (i <- indices) {
z(i) = myExpensiveFunction(x(i), y(i))
}
}
注意:我假設可以將myExpensiveFunction
更改myExpensiveFunction
按元素操作...
scala> def process(xs: Array[Int], ys: Array[Int], f: (Seq[Int], Seq[Int]) => Double): Array[Double] = {
| val ux = xs.distinct
| val zs = Array.fill(xs.size)(Double.NaN)
| for(x <- ux) {
| val idx = xs.indices.filter{ i => xs(i) == x }
| val res = f(idx.map(xs), idx.map(ys))
| idx foreach { i => zs(i) = res }
| }
| zs
| }
process: (xs: Array[Int], ys: Array[Int], f: (Seq[Int], Seq[Int]) => Double)Array[Double]
scala> val xs = Array(1,2,1,2,3)
xs: Array[Int] = Array(1, 2, 1, 2, 3)
scala> val ys = Array(1,2,3,4,5)
ys: Array[Int] = Array(1, 2, 3, 4, 5)
scala> val f = (a: Seq[Int], b: Seq[Int]) => a.sum/b.sum.toDouble
f: (Seq[Int], Seq[Int]) => Double = <function2>
scala> process(xs, ys, f)
res0: Array[Double] = Array(0.5, 0.6666666666666666, 0.5, 0.6666666666666666, 0.6)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.