2013-02-28 3 views
0

Я пытаюсь перевести следующий Matlab шаблон логико-индексирование в Scala код: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] в Scala. Каков наилучший способ сделать это?

Редактировать: Чтобы уточнить, я хочу обрабатывать партии (x, y) за один раз, сгруппированные по уникальному x и возвращать результат (z) с порядком, соответствующим начальному входу. Я открыт для сортировки x, но в итоге вам нужно вернуться к исходному несортированному заказу. Мое основное требование - обрабатывать все индексирование/сопоставление/сортировку четким и разумно эффективным способом.

+1

Для тех, кто не знаете MatLab, не могли бы вы уточнить, какие вычисления вы хотите сделать? –

+1

IIRC: «уникальный» Matlab возвращает уникальные значения в 'x', что переводится в' Set' в Scala. Выражение 'idx = x == ux (i);' дает булевой вектор индексов, которые соответствуют определенному уникальному значению. 'z',' x' и 'y' проецируются/сводятся к этим индексам. – bluenote10

+0

@RandallSchulz - Самая странная часть для пользователя Scala - это то, что в matlab, если вы индексируете вектор с бинарным вектором, он будет использовать это как фильтр, для которого используются индексы. Достаточно просто, за исключением того, что вы можете назначить в свой фильтр_. Итак, 'z (a) = y (a) + 1' будет устанавливать каждый элемент из' z' равным соответствующему элементу 'y' плюс один для тех же индексов элементов, где' a' истинно (фактически, 1). –

ответ

1

Большая часть этого довольно проста в 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 не как в большинстве других языков.)

+0

Спасибо Rex. Не могли бы вы расширить возможности Scala-esque/эффективный способ сделать это? – chriswynnyk

+1

@chriswynnyk - Ну, нет, потому что я понятия не имею, почему у меня есть дорогая функция, которая любит вектор с одинаковыми значениями «x» и кучей неидентичных 'y', и почему ответы должны поддерживаться в соответствии с оригинальный порядок для 'y's. –

+0

@chriswynnyk - Я по крайней мере предложил вариант «myExpensiveFunction» для каждого элемента. –

0

Важным моментом является получите Matlab's 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) 
Смежные вопросы