Julia:数组是不是包含特定的子数组
Posted
技术标签:
【中文标题】Julia:数组是不是包含特定的子数组【英文标题】:Julia: does an Array contain a specific sub-arrayJulia:数组是否包含特定的子数组 【发布时间】:2016-07-20 15:37:13 【问题描述】:在 julia 中,我们可以检查数组是否包含值,如下所示:
> 6 in [4,6,5]
true
但是,当尝试以特定顺序检查子数组时,这会返回 false:
> [4,6] in [4,6,5]
false
验证数组中是否存在特定子数组的正确语法是什么?
【问题讨论】:
问题中的第二个结果与其描述不符。它是4
和第一个结果的元组。
包Iterators.jl还提供了一个有用的函数subsets
,可以写成[4,6] in subsets([4,5,6])
。
这并没有给出正确的结果,即使给出了正确的结果,它也根本无法扩展(我用 Int64s 用不同长度的向量对所有这些进行了基准测试)
我误解了这个问题,对于那些想检查数组A
的每个元素(不考虑A
作为一个整体序列)是否包含在另一个数组B
,@987654330中的人@ 足以完成这项工作。
【参考方案1】:
请注意,您现在可以用点矢量化 in
:
julia> in([4,6,5]).([4, 6])
2-element BitArray1:
true
true
并与all
联系以获得您的答案:
julia> all(in([4,6,5]).([4, 6]))
true
【讨论】:
不错。如果你想避免重复项目怎么办?例如 all(in([4,6,5]).([4, 6, 6])) 应该返回 false,而不是 true。【参考方案2】:我认为值得一提的是,在 Julia 1.0 中,您有函数 issubset
> issubset([4,6], [4,6,5])
true
您也可以使用\subseteq
乳胶符号非常方便地调用它
> [4,6] ⊆ [4,6,5]
true
这对我来说看起来很优化:
> using Random
> x, y = randperm(10^3)[1:10^2], randperm(10^3);
> @btime issubset(x, y);
16.153 μs (12 allocations: 45.96 KiB)
【讨论】:
哇,太好了,这应该是选定的答案。在 Julia 1.2.0 中仍然有效 请注意,子集不同于subarray。[6,4]
不是 [4,6,5]
的子数组。【参考方案3】:
我最近用它来查找整数数组中的子序列。它不如@scott 的subset2(x,y)
好或快...但它返回索引。
function findsequence(arr::ArrayInt64, seq::ArrayInt64)
indices = Int64[]
i = 1
n = length(seq)
if n == 1
while true
occurrence = findnext(arr, seq[1], i)
if occurrence == 0
break
else
push!(indices, occurrence)
i = occurrence +1
end
end
else
while true
occurrence = Base._searchindex(arr, seq, i)
if occurrence == 0
break
else
push!(indices, occurrence)
i = occurrence +1
end
end
end
return indices
end
julia> @time findsequence(rand(1:9, 1000), [2,3])
0.000036 seconds (29 allocations: 8.766 KB)
16-element ArrayInt64,1:
80
118
138
158
234
243
409
470
539
589
619
629
645
666
762
856
【讨论】:
是的,这非常有用。我也不知道 Base._searchindex,我必须对其进行基准测试!我认为迭代器也很好,以免创建潜在的大向量(可能达到 seq 的长度)。【参考方案4】:制作一个性能良好的函数需要一点代码,但这比上面的issubvec
版本要快得多:
function subset2(x,y)
lenx = length(x)
first = x[1]
if lenx == 1
return findnext(y, first, 1) != 0
end
leny = length(y)
lim = length(y) - length(x) + 1
cur = 1
while (cur = findnext(y, first, cur)) != 0
cur > lim && break
beg = cur
@inbounds for i = 2:lenx
y[beg += 1] != x[i] && (beg = 0 ; break)
end
beg != 0 && return true
cur += 1
end
false
end
注意:如果该函数实际上返回子数组的开始位置(如果找到),或者如果没有返回 0,这也会更有用,类似于 findfirst/findnext 函数。
时序信息(第二个是使用我的subset2函数):
0.005273 seconds (65.70 k allocations: 4.073 MB)
0.000086 seconds (4 allocations: 160 bytes)
【讨论】:
第一个@time
结果(对于issubvec
)看起来可能包含编译——对于这样一个简单的调用来说,它太离群了。您可以重新检查(在计时之前进行编译运行)吗?
不是异常值 - 我当然是在运行之前编译的(没有 @time 宏)。我还测试了各种长度,我展示的一个是使用长度为 64K 的向量进行测试,搜索 4 的序列(向量中的最后 4 个值)。 issubvec
似乎有 O(n) 个分配,其中 n 是 y 的长度。
好的。测试用例很重要。如果您准确添加测试运行代码,我可以看到在这种情况下使用 Julia 0.5 与 0.4 是否重要。
最好作为要点发布,并将链接放在这里?
让我们离开它。确实,subset2
更优化了(如果要推送,还有更多优化),但可能需要另外讨论。【参考方案5】:
对于第三个条件,即向量 [4,6]
显示为 4,6,5
的子向量,建议使用以下函数:
issubvec(v,big) =
any([v == slice(big,i:(i+length(v)-1)) for i=1:(length(big)-length(v)+1)])
对于第二个条件,即对出现在set
向量中的els
向量中的每个元素,给出一个布尔值,建议如下:
function vecin(els,set)
res = zeros(Bool,size(els))
res[findin(els,set)]=true
res
end
使用 OP 中的向量,这些结果:
julia> vecin([4,6],[4,6,5])
2-element ArrayBool,1:
true
true
julia> issubvec([4,6],[4,6,5])
true
【讨论】:
issubvec 确实返回了正确的结果,但性能也不是很好,因为它进行了很多分配。使用@time
来查看由于分配过多而导致的性能下降是个好主意。
issubvec
肯定是未优化的,@ScottJones,但它的逻辑非常清晰 - 这是我的意图。您编写的函数更好(并且存在用于搜索子字符串/子向量的更优化算法)。我认为这样的通用子向量函数可能适合 Base(名称与字符串函数相似)。
实际上,我不得不与issubvec
的逻辑相结合,结合数组理解和使用slice
和any
函数。这并不是批评,我喜欢看到 Julia 的数组函数可以完成的强大功能,但来自 C/C++/Java 等。我不得不绞尽脑汁才能理解它。此外,我发现像这样的简短代码通常无法扩展,而我是一个性能专家?以上是关于Julia:数组是不是包含特定的子数组的主要内容,如果未能解决你的问题,请参考以下文章