如何在 Julia 中对多维数组的列使用 searchsorted?
How to use searchsorted on a column of a multidimensional array in Julia?
我有一个这样的排序二维数组:
testv = sortrows(["zebra" "N" 20; "jimi" "V" 100; "johnny" "V" 200; "pete" "P" 33; "jimi" "N" 20])
现在我基本上想检查是否有类似
的东西
"jimi" "N" x
在数组中。如果是,我将增加 x,否则我将添加 "jimi" "N" 1
到数组。
执行此操作的懒惰方法只是遍历数组检查所有条目,或者编写我自己的二进制搜索,但我保持数组排序以尽量减少成本。如果有办法让我 searchsorted
为我做这件事,那就太理想了。
如果我可以在 "jimi"
上使用 searchsorted
也很好 - 我的理解是(如果有效的话)它会 return 一个 [=15] 的范围=] 出现在排序数组中?那很好,数组的第二列来自一个足够小的域,我不介意以缓慢的方式循环。
base julia 中没有很多函数可以处理二维矩阵的行(除了 sortrows - 请参阅 apropos("rows")
的输出)。这部分是因为具有不同类型列的矩阵表现不佳,部分是因为有一些很好的选择。这里有几个选项可能更适合您。
元组向量
通过使用元组向量而不是矩阵,您可以获得更好的性能和搜索、增长、插入、删除等的能力。它还确保每个 "row"(现在只是一个元素 - 一个元组)具有正确的类型。
julia> A = [("zebra", "N", 20), ("jimi", "V", 100), ("johnny", "V", 200), ("pete", "P", 33), ("jimi", "N", 20)];
julia> sort!(A) # Sort A in-place
5-element Array{(ASCIIString,ASCIIString,Int64),1}:
("jimi","N",20)
("jimi","V",100)
("johnny","V",200)
("pete","P",33)
("zebra","N",20)
julia> idxs = searchsorted(A, ("matt", "B", 100))
4:3
julia> isempty(idxs) && splice!(A, idxs, [("matt", "B", 100)])
0-element Array{(ASCIIString,ASCIIString,Int64),1}
julia> A
6-element Array{(ASCIIString,ASCIIString,Int64),1}:
("jimi","N",20)
("jimi","V",100)
("johnny","V",200)
("matt","B",100)
("pete","P",33)
("zebra","N",20)
自定义类型的向量
如果您要经常使用此类数据,另一种更有吸引力的选择是创建自定义类型。设置需要更多的工作,但它随后还允许您创建自己的方法来处理此类数据。
immutable MyData
name::UTF8String
initial::UTF8String
score::Int
end
# We have to tell Julia how to sort these types by defining isless
function Base.isless(a::MyData, b::MyData)
isless((a.name, a.initial, a.score), (b.name, b.initial, b.score))
end
julia> B = [MyData("zebra", "N", 20), MyData("jimi", "V", 100), MyData("johnny", "V", 200), MyData("pete", "P", 33), MyData("jimi", "N", 20)]
julia> sort!(B)
5-element Array{MyData,1}:
MyData("jimi","N",20)
MyData("jimi","V",100)
MyData("johnny","V",200)
MyData("pete","P",33)
MyData("zebra","N",20)
julia> idxs = searchsorted(B, MyData("matt", "B", 100))
julia> isempty(idxs) && splice!(B, idxs, [MyData("matt", "B", 100)])
一种方法是使用字典。也许这种方法在某种程度上回避了问题的字面意义,但它非常符合提供易于高效递增的集合的目标。
julia> VERSION
v"0.3.5"
julia> testv = ["zebra" "N" 20; "jimi" "V" 100; "johnny" "V" 200; "pete" "P" 33; "jimi" "N" 20]
创建一个字典,其键由字符串对构成,值是总计。请注意,顺序与操作数据无关,但可以很容易地对数据进行排序以进行展示
julia> dv = {[testv[i,1], testv[i,2]] => testv[i,3] for i in 1:size(testv)[1]}
Dict{Any,Any} with 5 entries:
ASCIIString["zebra","N"] => 20
ASCIIString["pete","P"] => 33
ASCIIString["jimi","N"] => 20
ASCIIString["jimi","V"] => 100
ASCIIString["johnny","V"] => 200
julia> for k in sort(collect(keys(dv)), by=(x -> join(x,"")))
println(k[1], " ", k[2], " ", dv[k])
end
jimi N 20
jimi V 100
johnny V 200
pete P 33
zebra N 20
根据需要增加集合
julia> k = ["mike", "S"]
julia> get!(dv, k, 0)
julia> dv[k] += 1
julia> k = ["matt", "B"]
julia> get!(dv, k, 0)
julia> dv[k] += 1
julia> k = ["jimi","N"]
julia> get!(dv, k, 0)
julia> dv[k] += 1
然后你有
julia> for k in sort(collect(keys(dv)), by=(x -> join(x,"")))
println(k[1], " ", k[2], " ", dv[k])
end
jimi N 21
jimi V 100
johnny V 200
matt B 1
mike S 1
pete P 33
zebra N 20
当然,还有很多可以添加到其中的润色,但我认为我已经展示了基本方法。如果您还有其他具体问题,我很乐意详细说明。
我应该告诉您如何获得您开始使用的那种数组:
julia> testv = [[k[1], k[2], dv[k]] for k in sort(collect(keys(dv)), by=(x -> join(x,"")))]
julia> testv = [i[j] for i in tv, j in 1:3]
7x3 Array{Any,2}:
"jimi" "N" 21
"jimi" "V" 100
"johnny" "V" 200
"matt" "B" 1
"mike" "S" 1
"pete" "P" 33
"zebra" "N" 20
我有一个这样的排序二维数组:
testv = sortrows(["zebra" "N" 20; "jimi" "V" 100; "johnny" "V" 200; "pete" "P" 33; "jimi" "N" 20])
现在我基本上想检查是否有类似
的东西"jimi" "N" x
在数组中。如果是,我将增加 x,否则我将添加 "jimi" "N" 1
到数组。
执行此操作的懒惰方法只是遍历数组检查所有条目,或者编写我自己的二进制搜索,但我保持数组排序以尽量减少成本。如果有办法让我 searchsorted
为我做这件事,那就太理想了。
如果我可以在 "jimi"
上使用 searchsorted
也很好 - 我的理解是(如果有效的话)它会 return 一个 [=15] 的范围=] 出现在排序数组中?那很好,数组的第二列来自一个足够小的域,我不介意以缓慢的方式循环。
base julia 中没有很多函数可以处理二维矩阵的行(除了 sortrows - 请参阅 apropos("rows")
的输出)。这部分是因为具有不同类型列的矩阵表现不佳,部分是因为有一些很好的选择。这里有几个选项可能更适合您。
元组向量
通过使用元组向量而不是矩阵,您可以获得更好的性能和搜索、增长、插入、删除等的能力。它还确保每个 "row"(现在只是一个元素 - 一个元组)具有正确的类型。
julia> A = [("zebra", "N", 20), ("jimi", "V", 100), ("johnny", "V", 200), ("pete", "P", 33), ("jimi", "N", 20)];
julia> sort!(A) # Sort A in-place
5-element Array{(ASCIIString,ASCIIString,Int64),1}:
("jimi","N",20)
("jimi","V",100)
("johnny","V",200)
("pete","P",33)
("zebra","N",20)
julia> idxs = searchsorted(A, ("matt", "B", 100))
4:3
julia> isempty(idxs) && splice!(A, idxs, [("matt", "B", 100)])
0-element Array{(ASCIIString,ASCIIString,Int64),1}
julia> A
6-element Array{(ASCIIString,ASCIIString,Int64),1}:
("jimi","N",20)
("jimi","V",100)
("johnny","V",200)
("matt","B",100)
("pete","P",33)
("zebra","N",20)
自定义类型的向量
如果您要经常使用此类数据,另一种更有吸引力的选择是创建自定义类型。设置需要更多的工作,但它随后还允许您创建自己的方法来处理此类数据。
immutable MyData
name::UTF8String
initial::UTF8String
score::Int
end
# We have to tell Julia how to sort these types by defining isless
function Base.isless(a::MyData, b::MyData)
isless((a.name, a.initial, a.score), (b.name, b.initial, b.score))
end
julia> B = [MyData("zebra", "N", 20), MyData("jimi", "V", 100), MyData("johnny", "V", 200), MyData("pete", "P", 33), MyData("jimi", "N", 20)]
julia> sort!(B)
5-element Array{MyData,1}:
MyData("jimi","N",20)
MyData("jimi","V",100)
MyData("johnny","V",200)
MyData("pete","P",33)
MyData("zebra","N",20)
julia> idxs = searchsorted(B, MyData("matt", "B", 100))
julia> isempty(idxs) && splice!(B, idxs, [MyData("matt", "B", 100)])
一种方法是使用字典。也许这种方法在某种程度上回避了问题的字面意义,但它非常符合提供易于高效递增的集合的目标。
julia> VERSION
v"0.3.5"
julia> testv = ["zebra" "N" 20; "jimi" "V" 100; "johnny" "V" 200; "pete" "P" 33; "jimi" "N" 20]
创建一个字典,其键由字符串对构成,值是总计。请注意,顺序与操作数据无关,但可以很容易地对数据进行排序以进行展示
julia> dv = {[testv[i,1], testv[i,2]] => testv[i,3] for i in 1:size(testv)[1]}
Dict{Any,Any} with 5 entries:
ASCIIString["zebra","N"] => 20
ASCIIString["pete","P"] => 33
ASCIIString["jimi","N"] => 20
ASCIIString["jimi","V"] => 100
ASCIIString["johnny","V"] => 200
julia> for k in sort(collect(keys(dv)), by=(x -> join(x,"")))
println(k[1], " ", k[2], " ", dv[k])
end
jimi N 20
jimi V 100
johnny V 200
pete P 33
zebra N 20
根据需要增加集合
julia> k = ["mike", "S"]
julia> get!(dv, k, 0)
julia> dv[k] += 1
julia> k = ["matt", "B"]
julia> get!(dv, k, 0)
julia> dv[k] += 1
julia> k = ["jimi","N"]
julia> get!(dv, k, 0)
julia> dv[k] += 1
然后你有
julia> for k in sort(collect(keys(dv)), by=(x -> join(x,"")))
println(k[1], " ", k[2], " ", dv[k])
end
jimi N 21
jimi V 100
johnny V 200
matt B 1
mike S 1
pete P 33
zebra N 20
当然,还有很多可以添加到其中的润色,但我认为我已经展示了基本方法。如果您还有其他具体问题,我很乐意详细说明。
我应该告诉您如何获得您开始使用的那种数组:
julia> testv = [[k[1], k[2], dv[k]] for k in sort(collect(keys(dv)), by=(x -> join(x,"")))]
julia> testv = [i[j] for i in tv, j in 1:3]
7x3 Array{Any,2}:
"jimi" "N" 21
"jimi" "V" 100
"johnny" "V" 200
"matt" "B" 1
"mike" "S" 1
"pete" "P" 33
"zebra" "N" 20