在 Julia 中将元组向量转换为矩阵

时间:2021-07-27 11:05:43

标签: matrix tuples julia

假设我们有一个函数,它给了我们以下内容:

julia> ExampleFunction(Number1, Number2)
5-element Vector{Tuple{Int64, Int64}}:
 (2, 2)
 (2, 3)
 (3, 3)
 (3, 2)
 (4, 2)

我想转换 Vector{Tuple{Int64, Int64}} 转换为矩阵,或者在我的情况下,我想将其转换为 5x2 矩阵。

2 个答案:

答案 0 :(得分:3)

从您的问题中并不完全清楚长度为 2 的元组的 5 元素向量(总共有 10 个元素)应如何转换为包含 6 个元素的 3x2 矩阵,但假设您的意思是 5x2,这是一种方法这样做:

julia> x = [(1,2), (2, 3), (3, 4)]
3-element Vector{Tuple{Int64, Int64}}:
 (1, 2)
 (2, 3)
 (3, 4)

julia> hcat(first.(x), last.(x))
3×2 Matrix{Int64}:
 1  2
 2  3
 3  4

编辑:正如 Phips 在下面提到的替代方案,这里是 Julia 1.7beta3、Windows 10 的快速基准测试 - 我也加入了循环版本,因为在 Julia 中尝试直接循环总是有意义的:

julia> convert_to_tuple1(x) = hcat(first.(x), last.(x))
convert_to_tuple1 (generic function with 1 method)

julia> convert_to_tuple2(x) = PermutedDimsArray(reshape(foldl(append!, x, init = Int[]), 2, :), (2, 1))
convert_to_tuple2 (generic function with 1 method)

julia> function convert_to_tuple3(x)
           out = Matrix{eltype(x[1])}(undef, length(x), length(x[1]))
           for i ∈ 1:length(x)
               for j ∈ 1:length(x[1])
                   out[i, j] = x[i][j]
               end
           end
           out
       end
convert_to_tuple3 (generic function with 1 method)

julia> xs = [(rand(1:10), rand(1:10)) for _ ∈ 1:1_000_000];

julia> using BenchmarkTools

julia> @btime convert_to_tuple1($xs);
  15.789 ms (6 allocations: 30.52 MiB)

julia> @btime convert_to_tuple2($xs);
  22.067 ms (21 allocations: 18.91 MiB)

julia> @btime convert_to_tuple3($xs);
  7.286 ms (2 allocations: 15.26 MiB)

(进一步编辑以添加 $ 以将 xs 插值到基准中)

答案 1 :(得分:3)

最快的代码是非复制代码。在另一篇文章的示例中,这会将时间从毫秒减少到纳秒:

julia> xs
1000000-element Vector{Tuple{Int64, Int64}}:
 (5, 1)
 (4, 3)
 ⋮
 (1, 4)
 (9, 2)

julia> @btime reshape(reinterpret(Int, $xs), (2,:))'
  10.611 ns (0 allocations: 0 bytes)
1000000×2 adjoint(reshape(reinterpret(Int64, ::Vector{Tuple{Int64, Int64}}), 2, 1000000)) with eltype Int64:
  5   1
  4   3
  ⋮
  1   4
  9   2

对于复制代码来说,最快的将是:

function convert_to_tuple4(x)
   out = Matrix{eltype(x[1])}(undef, length(x), length(x[1]))
   for i ∈ 1:length(x)
         @inbounds @simd for j ∈ 1:length(x[1])
             out[i, j] = x[i][j]
         end
   end
   out
end

基准:

julia> @btime convert_to_tuple3($xs);
  3.488 ms (2 allocations: 15.26 MiB)

julia> @btime convert_to_tuple4($xs);
  2.932 ms (2 allocations: 15.26 MiB)