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 的逻辑相结合,结合数组理解和使用sliceany 函数。这并不是批评,我喜欢看到 Julia 的数组函数可以完成的强大功能,但来自 C/C++/Java 等。我不得不绞尽脑汁才能理解它。此外,我发现像这样的简短代码通常无法扩展,而我是一个性能专家?

以上是关于Julia:数组是不是包含特定的子数组的主要内容,如果未能解决你的问题,请参考以下文章

如何检查字符串是不是包含 JavaScript 预定义数组中存在的子字符串?

如何修改数组中特定子文档中的字段?

获取具有特定键/值对的二维数组中的子数组

需要在特定索引处重叠数组的子数组

如何通过数组检查字符串是不是具有匹配的子字符串

如何按特定的子数组值对多维数组进行分组?