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

Convert a tuple vector into a matrix in 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 的元组的 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 的快速基准测试,Windows10 - 我也加入了一个循环版本,因为尝试一个简单的方法总是有意义的在 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 插值到基准中)

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

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)