假设我们有一个矩阵:
A = [1.0 2.0 3.0; 4.0 5.0 6.0] #2×3 Matrix{Float64}
还有一条记录:
b = [1.0 2.0 3.0] #1×3 Matrix{Float64}
什么是在Julia中检查记录b是否存在于矩阵A中最有效的方法?
在Julia中执行b in A会返回false。
当我们需要检查大型矩阵(许多维度和许多行)时,编写嵌套的for循环似乎效率低下。
假设我们有一个矩阵:
A = [1.0 2.0 3.0; 4.0 5.0 6.0] #2×3 Matrix{Float64}
还有一条记录:
b = [1.0 2.0 3.0] #1×3 Matrix{Float64}
vec(b) in eachrow(A)
true
对于大型n维数组,可以使用
vec(b) in eachslice(A, dims=1)
true
如果矩阵中的行未排序,我会直接执行以下操作:
findfirst(==(vec(b)), eachrow(A))
searchsorted
。这篇回答是在Przemyslaw Szufel和AboAmmar提供的建议基础上进行补充和拓展的,旨在提供一个效率比较的参考:
using BenchmarkTools
A = [1.0 2.0 3.0; 4.0 5.0 6.0]
b = [1.0 2.0 3.0]
function my_findfirst(A, b)
if(findfirst(==(vec(b)), eachrow(A)) !== nothing)
return true
end
return false
end
function my_eachslice(A, b)
if vec(b) in eachslice(A, dims=1)
return true
end
return false
end
function my_eachrow(A,b)
if (vec(b) in eachrow(A))
return true
end
return false
end
@btime my_findfirst($A, $b) #66.846 ns (2 allocations: 80 bytes)
@btime my_eachslice($A, $b) #305.164 ns (5 allocations: 144 bytes)
@btime my_eachrow($A, $b) # 66.846 ns (2 allocations: 80 bytes)
function my_scancolumnfirst(A, b)
N = size(A,1)
c = @view A[:,1]
bv = vec(b)
b1 = bv[1]
@inbounds for i=1:N
if c[i]==b1 && bv==@view A[i,:]
return true
end
end
return false
end
一个样例基准测试:
A = rand(500,500);
b = A[350,:];
using BenchmarkTools
@btime my_findfirst($A, $b)
# 2.682 μs (0 allocations: 0 bytes)
# true
@btime my_scancolumnfirst($A, $b)
# 907.333 ns (0 allocations: 0 bytes)
# true
自定义版本显示效果提高了>2倍。
vec(b) in eachrow(A)
与findfirst(==(vec(b)), eachrow(A))
速度相同,但前者更加清晰易懂。我建议在 n 维数组中使用eachslice
。 - AboAmmar