2013-02-28 15 views
0

我想下面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 

假设我在斯卡拉val x: Array[Int]工作。做这个的最好方式是什么?为了澄清,我正在寻找一次处理(x,y)的批次,按唯一x分组,并返回一个结果(z),其中的顺序与初始输入相对应。我打算对x进行排序,但最终需要回到原始未排序的顺序。我的主要要求是以清晰和合理有效的方式处理所有的索引/映射/排序。

+1

对于那些谁不知道MatLab,你能澄清你想要做什么计算吗? – 2013-02-28 16:16:52

+1

IIRC:Matlab的'unique'返回'x'中的唯一值,这转换为Scala中的Set。表达式'idx = x == ux(i);'给出一个索引的布尔向量,它对应于某个唯一值。 'z','x'和'y'被投射/减少到这些指数。 – bluenote10 2013-02-28 16:38:34

+0

@RandallSchulz - 对Scala用户来说最奇怪的部分是在matlab中,如果你用一个二进制向量索引一个向量,它将使用它作为过滤器来使用哪个索引。很简单,除了_you可以分配到你的filter_。所以'z(a)= y(a)+ 1'会将'z'的每个元素设置为等于'y'的相应元素加上一个元素索引,其中'a'为真(实际上是1)。 – 2013-02-28 16:42:20

回答

1

其中大部分内容在Scala中相当简单;唯一有点不同寻常的是独特的x指数。在斯卡拉你可以用'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“自然”的计算是不喜欢那些在大多数其他语言。)

+0

感谢雷克斯。你可以扩展一个更加斯卡拉式/有效的方式来做到这一点吗? – chriswynnyk 2013-02-28 16:35:10

+1

@chriswynnyk - 嗯,不,因为我不知道为什么我有一个昂贵的函数,它喜欢一个相同的'x'值的矢量和一堆不相同的'y's,以及为什么答案需要与原来的'y's顺序。 – 2013-02-28 16:36:46

+0

@chriswynnyk - 我至少提出了每个元素“myExpensiveFunction”变体。 – 2013-02-28 17:11:16

0

重要的一点是得到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到元素方面的操作...

0
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)