获得在Julia中将数组拆分为两个大小相同的组的所有组合

时间:2013-10-04 01:38:20

标签: combinations julia

给定一个包含20个数字的数组,我想提取两个组的所有可能组合,每个组中有十个数字,顺序并不重要。

combinations([1, 2, 3], 2)

Julia中的

会给我从数组中提取的两个数字的所有可能组合,但我也需要那些未绘制的数字......

3 个答案:

答案 0 :(得分:1)

您可以使用setdiff来确定任何向量中缺少的项目,例如

y = setdiff(1:5, [2,4])

收益[1,3,5]

答案 1 :(得分:1)

在玩了一下之后,我想出了这个代码,这似乎有效。我相信它可以写得更优雅等等。

function removeall!(remove::Array, a::Array)
    for i in remove
        if in(i, a)
            splice!(a, indexin([i], a)[1])
        end
    end
end

function combinationgroups(a::Array, count::Integer)
    result = {}
    for i in combinations(a, count)
        all = copy(a)
        removeall!(i, all)
        push!(result, { i; all } )
    end
    result
end

combinationgroups([1,2,3,4],2)

6-element Array{Any,1}:
 {[1,2],[3,4]}
 {[1,3],[2,4]}
 {[1,4],[2,3]}
 {[2,3],[1,4]}
 {[2,4],[1,3]}
 {[3,4],[1,2]}

答案 2 :(得分:0)

根据@ tholy的评论而不是使用实际数字,我可以使用位置(以避免数字不唯一的问题)和setdiff获取“其他组”(未选择的数字),我出现了以下内容。第一个函数基于索引从数组中获取值(即,arraybyindex([11,12,13,14,15],[2,4])=> [12,14])。这似乎可能是标准库的一部分(我确实在寻找它,但可能已经错过了它。)

第二个功能执行组合组正在执行的操作,创建特定大小的所有组及其补充。它可以单独调用,也可以通过第三个函数调用,后者提取所有可能大小的组。有可能这一切都写得更快,更具有特异性。

function arraybyindex(a::Array, indx::Array)
    res = {}
    for e in indx
        push!(res, a[e])
    end

    res
end
function combinationsbypos(a::Array, n::Integer)
    res = {}
    positions = 1:length(a)
    for e in combinations(positions, n)          
        push!(res, { arraybyindex(a, e) ; arraybyindex(a, setdiff(positions, e)) })
    end
    res
end

function allcombinationgroups(a::Array)
    maxsplit = floor(length(a) / 2)
    res = {}
    for e in 1:5
        println("Calculating for $e, so far $(length(res)) groups calculated")
        push!(res, combinationsbypos(a, e))
    end
    res
end

在IJulia上使用3岁的MacBook pro进行此操作

@time c=allcombinationgroups([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20])
println(length(c))
c

Calculating for 1, so far 0 groups calculated
Calculating for 2, so far 20 groups calculated
Calculating for 3, so far 210 groups calculated
Calculating for 4, so far 1350 groups calculated
Calculating for 5, so far 6195 groups calculated
Calculating for 6, so far 21699 groups calculated
Calculating for 7, so far 60459 groups calculated
Calculating for 8, so far 137979 groups calculated
Calculating for 9, so far 263949 groups calculated
Calculating for 10, so far 431909 groups calculated
elapsed time: 11.565218719 seconds (1894698956 bytes allocated)
Out[49]:
616665

616665-element Array{Any,1}:
 {{1},{2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}}
 {{2},{1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}}
  ⋮                                                       
 {{10,12,13,14,15,16,17,18,19,20},{1,2,3,4,5,6,7,8,9,11}}
 {{11,12,13,14,15,16,17,18,19,20},{1,2,3,4,5,6,7,8,9,10}}

即。每秒计算53,334组。

作为对比,使用相同的外部allcombinationgroups函数,但是使用对组合组的调用替换对combinationbypos的调用(参见上一个答案),速度要慢10倍。

然后我按照@tholy的建议使用true或false标记重写索引组的数组(我无法弄清楚如何使用[]来使它工作,所以我明确地使用了setindex!并将它移动到一个函数中另外10倍加速!116秒内616,665组!

最终代码(到目前为止):

function combinationsbypos(a::Array, n::Integer)
    res = {}
    positions = 1:length(a)
    emptyflags = falses(length(a))
    for e in combinations(positions, n)       
        flag = copy(emptyflags)
        setindex!(flag, true, e)
        push!(res, {a[flag] ; a[!flag]} )
    end
    res
end

function allcombinationgroups(a::Array)
    maxsplit = floor(length(a) / 2)
    res = {}
    for e in 1:maxsplit
        res = vcat(res, combinationsbypos(a, e))
    end
    res
end