Julia:有效地将压缩元组映射到元组



我正在寻找一种有效的方法来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

CCD_ 4和CCD_。但是,在任何情况下,这都会分配内存。以有效的方式做到这一点的好方法是什么?

试试怎么样

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

如果ab是数组而不是元组,则可以执行此操作。参见以下示例:

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

只有当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用于浪费的一个

最新更新