我经常想要遍历数据帧的长数组或列,并为每个项目查看它是否是另一个数组的成员。而不是做
giant_list = ["a", "c", "j"]
good_letters = ["a", "b"]
isin = falses(size(giant_list,1))
for i=1:size(giant_list,1)
isin[i] = giant_list[i] in good_letters
end
是否有任何矢量化(双向矢量?)方式在朱莉娅这样做?与基本操作符类似,我想做类似的事情
isin = giant_list .in good_letters
我意识到这可能是不可能的,但我只是想确保我没有遗漏一些东西。我知道我可能会使用DataStructures中的DefaultDict做类似但不知道基础中的任何内容。
indexin
函数执行类似于您想要的操作:
indexin(a, b)
返回包含
b
中最高索引的向量,该值为a
中b
成员的每个值。只要a
不是b
的成员,输出向量就包含0。
因为你需要giant_list
中每个元素的布尔值(而不是good_letters
中的索引),你可以简单地做:
julia> indexin(giant_list, good_letters) .> 0
3-element BitArray{1}:
true
false
false
implementation of indexin
非常简单,如果您不关心b
中的指数,请指出如何优化此方法:
function vectorin(a, b)
bset = Set(b)
[i in bset for i in a]
end
只有一组有限的名称可以用作中缀运算符,因此无法将其用作中缀运算符。
你可以使用in
在Julia v0.6中很容易地矢量化unified broadcasting syntax。
julia> in.(giant_list, (good_letters,))
3-element Array{Bool,1}:
true
false
false
请注意使用单元素元组的scalarification的good_letters
。或者,您可以使用Scalar
类型,例如StaticArrays.jl中引入的类型。
Julia v0.5支持相同的语法,但需要一个特殊的scalarificiation函数(或前面提到的Scalar
类型):
scalar(x) = setindex!(Array{typeof(x)}(), x)
之后
julia> in.(giant_list, scalar(good_letters))
3-element Array{Bool,1}:
true
false
false
这个问题有一些现代(即Julia v1.0)解决方案:
首先,更新标量策略。使用Ref
对象可以实现标量广播,而不是使用1元素元组或数组:
julia> in.(giant_list, Ref(good_letters))
3-element BitArray{1}:
true
false
false
通过广播中缀∈
(\in
TAB)运算符可以实现相同的结果:
julia> giant_list .∈ Ref(good_letters)
3-element BitArray{1}:
true
false
false
此外,使用一个参数调用in
会创建一个Base.Fix2
,稍后可以通过广播调用应用它。然而,与简单地定义函数相比,这似乎具有有限的益处。
julia> is_good1 = in(good_letters);
is_good2(x) = x in good_letters;
julia> is_good1.(giant_list)
3-element BitArray{1}:
true
false
false
julia> is_good2.(giant_list)
3-element BitArray{1}:
true
false
false
总而言之,使用带有.∈
的Ref
可能会导致最短,最干净的代码。
findin()
没有给你一个布尔掩码,但你可以很容易地使用它来为一个数组/ DataFrame配置另一个数组中包含的值:
julia> giant_list[findin(giant_list, good_letters)]
1-element Array{String,1}:
"a"