【问题标题】:Julia: Unique sets of n elements with replacementJulia:具有替换的唯一 n 个元素集
【发布时间】:2014-10-11 10:55:14
【问题描述】:

给定一个向量 v = [1,..,n],我尝试在 julia 中计算所有唯一的 n 个元素的集合并替换。

由于我想对较大的 n 值执行此操作,因此我正在寻找一种有效的解决方案,可能使用迭代器。

例如,让我们考虑v = [1, 2, 3]:这应该会导致[1,1,1], [1,1,2], [1,1,3], [1,2,2], [1,2,3], [1,3,3], [2,2,2], [2,2,3], [2,3,3], [3,3,3]。唯一的意思是,如果[1,1,2] 是一个解决方案,那么它的任何排列[1,2,1], [2,1,1] 都不是。

我当前的解决方案基于partitions 函数,但不允许我限制元素 [1,..,n] 的计算

for i in n:n^2
  for j in partitions(i, n)
    ## ignore sets which exceed the range [1,n]
    if maximum(j) <= n
      ## accept as solution
    end
  end
end

【问题讨论】:

    标签: combinatorics julia


    【解决方案1】:

    我猜,它不会比一行短(使用迭代器)。

    using IterTools
    import Combinatorics.combinations
    n=3
    collect(imap(c -> Int[c[k]-k+1 for k=1:length(c)],combinations(1:(2n-1),n)))
    

    【讨论】:

      【解决方案2】:

      我相信您正在从 Iterators 包中寻找产品功能。在您的情况下, product(v,v,v) 应该执行所需的操作。

      【讨论】:

      • 产品返回所有可能的组合,而不仅仅是唯一的组合(例如,它将返回 [1,1,2]、[1,2,1] 和 [2,1,1]上面的例子)。我已编辑问题以使其更清楚。
      【解决方案3】:

      在 julia v0.5.0 中,combinatorics.jl 有一个 with_replacement_combinations 方法。

      julia> collect(with_replacement_combinations(1:4,3))
      20-element Array{Array{Int64,1},1}:
       [1,1,1]
       [1,1,2]
       [1,1,3]
       [1,1,4]
       [1,2,2]
       [1,2,3]
       [1,2,4]
       [1,3,3]
       [1,3,4]
       [1,4,4]
       [2,2,2]
       [2,2,3]
       [2,2,4]
       [2,3,3]
       [2,3,4]
       [2,4,4]
       [3,3,3]
       [3,3,4]
       [3,4,4]
       [4,4,4]
      

      【讨论】:

        【解决方案4】:

        这是一个计算所需集合的函数:

        function calcset(n=3)
            res = []
            for c in combinations([1:(2n-1)],n-1)
                c3 = [c,2n].-[0,c]
                push!(res,vcat([fill(i,c3[n-i+1]-1) for i=1:n]...))
            end
            return res
        end
        calcset(3)
        

        可能有更好的编码方式,但这应该足够了。 请注意,结果是通过重复的push!s 生成的,因此如果需要,这很容易变成一个迭代器。

        【讨论】:

          【解决方案5】:

          并以迭代器形式:

          import Base: start, next, done, eltype, length
          type ImageTypeIterator
              inneritr::Base.Combinations{Array{Int64,1}}
              n::Int
          end
          imagetype(n::Int) = ImageTypeIterator(combinations([1:(2n-1)],n-1),n)
          eltype(itr::ImageTypeIterator) = Array{Int64,1}
          start(itr::ImageTypeIterator) = start(itr.inneritr)
          function next(itr::ImageTypeIterator,s)
              (c,s) = next(itr.inneritr,s)
              c3 = [c,2*itr.n].-[0,c]
              (vcat([fill(i,c3[itr.n-i+1]-1) for i=1:itr.n]...),s)
          end
          done(itr::ImageTypeIterator,s) = done(itr.inneritr,s)
          length(itr::ImageTypeIterator) = length(itr.inneritr)
          # test with [1,2,3]
          for t in imagetype(3) println(t) ; end
          

          最后的测试应该打印问题中的集合。

          顺便说一句,ImageTypeIterator 的名称是在查看函数 f : [1:n] -> [1:n] 时尝试将集合表征为不同类型的原像大小。但不同的解释可能是合适的。 cmets欢迎其他名称建议。

          更快?/更清晰?实现可以使用:

          imagetype(n::Int) = ImageTypeIterator(combinations([1:(2n-1)],n),n)
          function next(itr::ImageTypeIterator,s)
              (c,s) = next(itr.inneritr,s)
              v = Array(Int,itr.n)
              j = 1 ; p = 1
              for k=1:itr.n
                  while !(j in c) j += 1 ; p += 1 ; end
                  v[k] = p
                  j += 1
              end
              (v,s)
          end
          

          与上面的逻辑相同,但没有过多的切片。该逻辑采用 2n-1 的子集,并将非间隙视为重复值,将间隙视为前进到下一个值的触发器。

          【讨论】:

            【解决方案6】:

            好的,使用 Iterators.jl 的更简单的版本:

            using Iterators
            function ff(c)
                v = Array(Int,length(c))
                j = 1 ; p = 1
                for k=1:length(c)
                    while !(j in c) j += 1 ; p += 1 ; end
                    v[k] = p
                    j += 1
                end
                v
            end
            # test
            n = 3
            for t in imap(ff,combinations([1:(2n-1)],n)) println(t) ; end
            

            这可能是最简单的版本,尽管在方法上与其他答案相同。

            本着简洁的精神:

            using Iterators
            ff(c) = begin 
                j=1;p=1; [(while !(j in c) j+=1;p+=1 ; end ; j+=1 ; p) for k=1:length(c)] 
            end
            n = 3 # test
            for t in imap(ff,combinations([1:(2n-1)],n)) println(t) ; end
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-09-01
              • 1970-01-01
              • 2015-11-19
              • 2020-07-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-11-29
              相关资源
              最近更新 更多