Джулия: Эффективно отобразить кортежи на молнии для Tuple - PullRequest
2 голосов
/ 30 октября 2019

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

Чтобы было ясно: я счастлив, что не использую zip. Подойдет любое решение, которое позволяет совместно выполнять итерацию по нескольким кортежам, если только оно избегает выделения кучи.

Пример:

a = (1, 2, 3, 4)
b = ("a", "b", "c", "d")

# Just placeholder for an arbitrary non-allocating operation with i and j
do_something(i,j) = (i,j)

# Naive construction `Tuple` from resulting `Array` will allocate.  
c1 = map(zip(a, b)) do (i, j)
    do_something(i,j)
end |> Tuple

# Naive conversion to `Tuple` before mapping will allocate.
c2 = map(Tuple(zip(a, b))) do (i, j)
    do_something(i,j)
end

Оба c1 и c2 будут иметьжелаемый тип. Однако в любом случае это выделит память. Что является хорошим способом сделать это эффективным способом?

Ответы [ 3 ]

1 голос
/ 01 ноября 2019

Как насчет того, чтобы попробовать что-то вроде

julia> map((i,j)->(i,j), a, b)
((1, "a"), (2, "b"), (3, "c"), (4, "d"))

Или для более интересного примера,

julia> map((i,j)->j^i, a, b)
("a", "bb", "ccc", "dddd")
1 голос
/ 30 октября 2019

Вы можете сделать это, если a и b являются массивами, а не кортежами. Смотрите пример ниже:

julia> a1 = [1, 2, 3, 4];

julia> b1 = ["a", "b", "c", "d"];

julia> z = do_something.(view.(Ref(a1),1:4),  view.(Ref(b1),1:4))
4-element Array{Tuple{SubArray{Int64,0,Array{Int64,1},Tuple{Int64},true},SubArray{String,0,Array{String,1},Tuple{Int64},true}},1}:
 (1, "a")
 (2, "b")
 (3, "c")
 (4, "d")
0 голосов
/ 30 октября 2019

этот код будет работать только в том случае, если f(a,b) создает одинаковый тип для каждого элемента кортежа и только два элемента (но его можно изменить в соответствии с вашей операцией):

function mytuplemaker(f,a,b)
if (len=length(a)) == length(b) #asigns len and compares at the same time, neat trick
    x1 = f(a[1],b[1]) #wastes a calculation to obtain the resulting type
    T = typeof(x1) 
    return NTuple{len,T}(f(a[i],b[i]) for i = 1:len)
else
    return nothing
end
end

некоторые тесты:

julia> @btime map(Tuple(zip($a, $b))) do (i, j)
           do_something(i,j)
       end
  377.340 ns (13 allocations: 528 bytes)
((1, "a"), (2, "b"), (3, "c"), (4, "d"))
@btime  map(zip($a, $b)) do (i, j)
           do_something(i,j)
       end |> Tuple
  377.223 ns (10 allocations: 480 bytes)
((1, "a"), (2, "b"), (3, "c"), (4, "d"))
@btime mytuplemaker(do_something,$a,$b)
  38.655 ns (5 allocations: 176 bytes)
((1, "a"), (2, "b"), (3, "c"), (4, "d"))

его 5 распределений, по одному на элемент +1 для потраченного впустую

...