Векторизация - PullRequest
       11

Векторизация

3 голосов
/ 21 марта 2019

Я хотел бы иметь возможность разбивать массив кортежей на функцию в векторизованном виде.Например, если у меня есть следующая функция,

function foo(x, y)
    x + y
end

и следующий массив кортежей,

args_array = [(1, 2), (3, 4), (5, 6)]

, тогда я мог бы использовать понимание списка для получения желаемого результата:

julia> [foo(args...) for args in args_array]
3-element Array{Int64,1}:
  3
  7
 11

Однако я бы хотел использовать для этой операции нотацию точечной векторизации:

julia> foo.(args_array...)
ERROR: MethodError: no method matching foo(::Int64, ::Int64, ::Int64)

Но, как вы видите, этот конкретный синтаксис не работает.Есть ли векторизованный способ сделать это?

Ответы [ 3 ]

8 голосов
/ 21 марта 2019

foo.(args_array...) не работает, потому что он делает:

foo.((1, 2), (3, 4), (5, 6))
# which is roughly equivalent to
[foo(1,3,5), foo(2,4,6)]

Другими словами, он принимает каждый элемент args_array в качестве отдельного аргумента и затем передает foo поверх этих аргументов.Вы хотите транслировать foo через элементы напрямую.Проблема в том, что выполняется:

foo.(args_array)
# is roughly equivalent to:
[foo((1,2)), foo((3,4)), foo((5,6))]

Другими словами, синтаксис широковещания просто передает каждый кортеж в качестве единственного аргумента foo.Мы можем исправить это с помощью простой промежуточной функции:

julia> bar(args) = foo(args...);

julia> bar.(args_array)
3-element Array{Int64,1}:
  3
  7
 11

Теперь вы делаете то, что хотите!Вам даже не нужно создавать второй аргумент, если вы не хотите.Это в точности эквивалентно:

julia> (args->foo(args...)).(args_array)
3-element Array{Int64,1}:
  3
  7
 11

И на самом деле вы можете легко обобщить это:

julia> splat(f) = args -> f(args...);

julia> (splat(foo)).(args_array)
3-element Array{Int64,1}:
  3
  7
 11
1 голос
/ 21 марта 2019

Вы можете zip args_array, который эффективно транспонирует массив кортежей:

julia> collect(zip(args_array...))
2-element Array{Tuple{Int64,Int64,Int64},1}:
 (1, 3, 5)
 (2, 4, 6)

Затем вы можете транслировать foo по транспонированному массиву (фактически итератору) кортежей:

julia> foo.(zip(args_array...)...)
(3, 7, 11)

Однако, это возвращает кортеж вместо массива.Если вам нужно, чтобы возвращаемое значение было массивом, вы можете использовать любое из следующих несколько загадочных решений:

julia> foo.(collect.(zip(args_array...))...)
3-element Array{Int64,1}:
  3
  7
 11

julia> collect(foo.(zip(args_array...)...))
3-element Array{Int64,1}:
  3
  7
 11

julia> [foo.(zip(args_array...)...)...]
3-element Array{Int64,1}:
  3
  7
 11
0 голосов
/ 22 марта 2019

Как насчет

[foo(x,y) for (x,y) in args_array]
...