如何在Julia中的多维数组的列上使用searchsorted?

时间:2015-02-03 19:22:52

标签: multidimensional-array 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为我做这件事,那将是理想的。

如果我可以在searchsorted上使用"jimi",那也没关系 - 我的理解是(如果有效)它会返回"jimi"出现的范围排序的数组?那没关系,阵列的第二列来自一个足够小的域,我不介意慢慢地循环。

2 个答案:

答案 0 :(得分:2)

基础julia中没有很多函数可以处理二维矩阵的行(除了sortrows之外 - 参见apropos("rows")的输出)。这部分是因为具有不同类型列的矩阵表现不佳,部分原因是因为有一些很好的选择。这里有几个选项可能对你有用。

元组的向量

通过使用元组的向量而不是矩阵,您可以获得更好的性能以及搜索,增长,插入,删除等功能。它还可以确保每个“行”(现在只是一个元素 - 一个元组有适当的类型。

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

答案 1 :(得分:1)

一种方法是使用字典。也许这种方法在某种程度上避开了问题的字母,但它很好地适用于提供容易且有效增加的集合的目标。

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