列出n的所有有序分区


23

挑战是列出给定正整数的所有有序分区(组成(组合))n。这些数字从名单1n其总和n。例如,给定input n = 4,结果应为:

4
1,3
3,1
2,2
2,1,1
1,2,1
1,1,2
1,1,1,1

结果可以采用任何顺序,但是必须包含每个有序分区一次。这意味着n = 4[1, 1, 2][1, 2, 1]而且[2, 1, 1]必须是结果的一部分。

这是我自己的实现此目的的JavaScript代码:

function range(n) {
    for (var range = [], i = 0; i < n; range.push(++i));
    return range;
}

function composition(n) {
    return n < 1 ? [[]] : range(n).map(function(i) {
        return composition(n - i).map(function(j) {
            return [i].concat(j);
        });
    }).reduce(function(a, b) {
        return a.concat(b);
    });
}

Golfed,ES6(169 167 119 109 105 89 85个字节):

n=>n?[].concat(...[...Array(n)].map((x,i)=>i+1).map(b=>m(n-b).map(a=>[b,...a]))):[[]]

3
欢迎光临本站!您需要指定一个获胜标准。代码高尔夫也许吗?另外,它必须按特定顺序排列吗?如果是这样,通常如何定义顺序?我认为字典顺序将更有意义。还是更好,允许任何订单。在将其发布到此处之前,您可能希望使用沙盒应对未来的挑战
Luis Mendo

3
@Fatalize在这里[2 1 1]与[1 2 1]不同,与那里不同。我怀疑方法可能有很大不同
Luis Mendo

3
对于那些以欺骗手段封闭的人:您确定注释中指出的区别不相关吗?我没有投票赞成重新开放,因为我认为这把锤子也可以朝这个方向工作
Luis Mendo

3
我建议您暂时不要接受答案(即使您可以随时更改它),因为看到首页上接受的问题可能会让人们认为答案已经结束并且不参与。
xnor

5
这些有序分区的常用术语是“ composition ”。
格雷格·马丁

Answers:


7

Pyth,7个 6字节

7字节解决方案:

Pyth具有内置的整数分区./,因此7个字节中的5个正在获得排序。

{s.pM./

在线尝试!

说明:

     ./  Integer partition (sorted by default)
  .pM    get all the orderings of each of the partitions as a nested list of lists of orderings
 s       Flatten by one layer
{        Remove duplicates

6字节解决方案:

如果有列表,./将按顺序进行计算;剩下的就是再次使列表编号。

lMM./m

在线尝试!

说明:

     m  Get lists by gathering a list of [0, 1,...input] (I could use U as well)

   ./   Partition with orderings
 MM     Map an operation across each of the orderings lists of elements
l       where that operation is the length of the sublists

惊人。这是到目前为止我所见过的最小的!
driima

11

Haskell,37个字节

f 0=[[]]
f n=[a:x|a<-[1..n],x<-f$n-a]

xnor保存了两个字节。


1
看起来越直接f n=[a:x|a<-[1..n],x<-f$n-a]越短。
xnor

您不需要零位检查(given positive integer n ... numbers from 1 to n
nyro_0-16年

2
f 0=[[]]恰好是一个比f 1=[[1]]:) 更短的基本案例:
林恩

@xyLe_它使用了递归的基本情况。
xnor

啊,当然,你是对的,我的坏
nyro_0

10

Python,56个字节

f=lambda n:[x+[n-i]for i in range(n)for x in f(i)]or[[]]

递归溶液:的有序分区n是一些小的分区i0<=i<n,接着其余的n-i作为最后一个元素。对于基本情况,n=0仅具有空分区。


简单,小巧但可读性仍然很高。那就是我对Python的热爱。
driima

10

Python 2,61字节

f=lambda n,s='1,':1/n*[eval(s)]or f(n-1,'1+'+s)+f(n-1,'1,'+s)

这不是最短的方法,但是我真的很喜欢这种方法,因为它很奇怪。

递归生成和评估2**(n-1)字符串,例如

1+1+1+1,
1,1+1+1,
1+1,1+1,
1,1,1+1,
1+1+1,1,
1,1+1,1,
1+1,1,1,
1,1,1,1,

n=4。这些字符串计算得出表示所有分区的元组。在任何两个1之间的是+,将它们连接成一个数字,或者是,,将相邻部分分开。


我能做的最好的非递归版本是import re lambda n:map(lambda n:map(len,re.finall('10*',bin(n))),range(1<<n-1,1<<n))
Neil

1
对代码的解释确实会使它更漂亮。
noman pouigt

8

JavaScript(Firefox 30-57),63个字节

f=n=>n?[for(i of Array(n).keys())for(a of f(i))[n-i,...a]]:[[]]

12
Firefox 30+对于更成熟的Internet用户而言,听起来像是一种特殊的浏览器。
马丁·恩德

可能不会比这更短...
ETHproductions

任何其他浏览器中的JavaScript都无法解决这个问题吗?
driima

@Eternity我可以为您移植@xnor的其他答案:f=n=>n<2?[[1]]:f(n-1).map(([n,...a])=>r.push([1+n,...a],[1,n,...a]),r=[])&&r
尼尔

6

Mathematica,40个字节

Join@@Permutations/@IntegerPartitions@#&

Mathematica内置的整数分区不能提供所有有序分区,因此我们必须生成每个分区的所有可能排列,然后将结果展平。


6

CJam17 14字节

ri"X)"m*{~]p}/

在线尝试!

说明

我知道我说过使用笛卡尔积会更长,但是最终我找到了一种更有效使用它的方法。我认为这两种方法本身都很有趣,因此我将它们放在单独的文章中。

这仍然基于以下想法:我们可以选择n在将a附加1到当前分区或增加当前分区的最后一个元素之间的时间。在此解决方案中,我们通过生成2 n-1个与这些不同选择相对应的程序来做到这一点。

ri      e# Read input and convert to integer N.
        e# Decrement.
"X)"m*  e# Get all strings of length N which consist of 'X' and ')'. If
        e# we treat these strings as CJam code then 'X' pushes a 1 and ')'
        e# increments the top of the stack.
        e# Note that some of these strings will begin with an increment that
        e# doesn't have anything on the stack to work with. This will result in
        e# an error and terminate the program. Luckily, the programs are ordered
        e# such that all programs starting with 'X' are first in the list, so
        e# we get to print all the 2^(N-1) permutations before erroring out.
{       e# For each of these programs (well for the first half of them)...
  ~     e#   Evaluate the string as CJam code. This leaves the partition as
        e#   individual integers on the stack.
  ]p    e#   Wrap the stack in a list and pretty-print it.
}/

我看着这个,以为“ 那不可能是对的,它在评估以)开头的第一个字符串时会给出一个错误。所以我添加ed并测试。+1创造性地滥用错误。
彼得·泰勒

6

果冻7 6 字节

-1个字节感谢@Dennis(从一元转换ḅ1,而不是每个的总和S€€

1ẋŒṖḅ1

在线试用

怎么样?

1ẋŒṖḅ1 - Main link: n          e.g. 4
1ẋ     - repeat 1 n times          [1,1,1,1]
  ŒṖ   - partitions of a list     [[[1],[1],[1],[1]], [[1],[1],[1,1]], [[1],[1,1],[1]],
                                   [[1],[1,1,1]],     [[1,1],[1],[1]], [[1,1],[1,1]],
                                   [[1,1,1],[1]],     [[1,1,1,1]]]
    ḅ1 - from base 1 (vectorises)  [[1,1,1,1],        [1,1,2],         [1,2,1],
                                   [1,3],             [2,1,1],         [2,2],
                                   [3,1],             [4]]

5

Pure Bash,51岁

这是@xnor出色答案的一部分,它使用多个级别的bash扩展来实现所需的结果:

a=$[10**($1-1)]
eval echo \$[${a//0/{+,']\ $[}1'}],

伊迪恩

  • 第一行是一个简单的算术扩展来创建变量$a含有1随后n-1零。
  • 第一个扩展${a//0/{+,']\ $[}1'}用字符串的副本替换每个0in 。因此n = 4我们得到了字符串$a{+,']\ $[}1'1{+,']\ $[}1'{+,']\ $[}1'{+,']\ $[}1'
  • 前缀$[和后缀],$[1{+,']\ $[}1'{+,']\ $[}1'{+,']\ $[}1]
  • 这是一个大括号扩展,扩展为 $[1+1+1+1], $[1+1+1] 1, $[1+1] $[1+1], $[1+1] 1 1,...
  • 最后,将其进行算术扩展以提供所需的结果。

谨慎使用引号,反斜杠转义,并eval确保扩展以正确的顺序进行。


4

Ruby,61个字节

f=->n{n<1?[[]]:(1..n).map{|i|f[n-i].map{|x|x<<i}}.flatten(1)}

不打高尔夫球

f=->n{
  n < 1 ?
    [[]]
  :
    (1..n).map { |i|
      f[n-i].map { |x|
        x << i
      }
    }.flatten(1)
}

用法

p f[4]
# => [[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]]

2
iya!您能为不熟悉Ruby的人(如我)添加一点解释吗?
AdmBorkBork

x<<i比短[i]+x
m-chrzan

@TimmyD我添加了一个不完整的代码及其用法。
cia_rana

@ m-chrzan谢谢您的指教!我编辑了。
cia_rana '16

.flatten(1)是不是有.flatten 1什么原因?
Cyoce's

3

Brachylog,20个字节

~lL#++?,L:=f:{:0x}ad

在线尝试!

说明

在这种情况下,您会认为声明性语言会做得很好,但是由于的重载+和难以编写适当传播约束的求和谓词,所以这样做不是。

~lL                     L is a list of length Input
  L#+                   L is a list of non-negative integers
  L  +?,                The sum of the elements of L results in the Input
        L:=f            Find all values for the elements of L which satisfy those constraints
            :{:0x}a     Remove all 0s from each sublist of the result of Findall
                   d    Remove all duplicate sublists

我认为,如果您专注于整数,并且将其长度L设置 1与输入之间,则传播速度会更快。

@mat 这是我最初所做的,但是更长。由于+也适用于单个整数,因此我需要强制.成为的列表##,并且+也适用于列表的列表,因此我需要强加的元素.是整数:#$a
致命

因此,关键问题在于数据结构的默认性:当变量作为矢量化操作的参数出现时,您无法分辨该变量代表单个整数还是(可能是嵌套的)列表。这是一个棘手的问题,从最初的版本开始,寻找可以简化此过程的合适语言结构,可能会有一种优雅的解决方案。无论如何都不错!

3

CJam,19个字节

Lari{_1af.+1@f+|}*p

在线尝试!

说明

CJam没有用于整数分区的有用的内置组合器。因此,我们将手动执行此操作。要查找整数的所有有序分区n,我们可以查看一个分区列表,n并考虑插入分隔符的所有可能方法。然后,我们将1每个部分中的s 相加。示例n = 3

1 1 1 => 3
1 1|1 => 2|1
1|1 1 => 1|2
1|1|1 => 1|1|1

我尝试使用笛卡尔积来生成所有这些分隔符,但是最终以21个字节结尾。取而代之的是,我回到了这种用于生成功率集的旧技术(这是基于丹尼斯(Dennis's)的旧答案,但我现在找不到它)。这个想法是这样的:要生成所有分区,我们可以从一个空列表开始。然后n我们可以做出二元决策:要么追加一个1(对应于以上示例中的分隔符),要么增加列表的最后一个值(对应于不包含分隔符)。要生成所有分区,我们只需在每个步骤执行两项操作,并保留所有可能的输出供下一步使用。事实证明,在CJam中,第一个元素的前缀和增量较短,但是原理保持不变:

La       e# Push [[]] onto the stack. The outer list will be the list of
         e# all possible partitions at the current iteration, and we initialise
         e# it to one empty partition (basically all partitions of 0).
ri       e# Read input and convert to integer N.
{        e# Repeat this N times...
  _      e#   Duplicate the list of partitions of i-1.
  1af.+  e#   Increment the first element in each of these. This is done
         e#   by performing a pairwise addition between the partition and [1].
         e#   There is the catch that in the first iteration this will turn
         e#   the empty array into [1], so it's equivalent to the next step.
  1@f+   e#   Pull up the other copy of the list of partitions of i-1 and
         e#   prepend a 1 to each of them.
  |      e#   Set union. This gets rid of the duplicate result from the first
         e#   iteration (in all other iterations this is equivalent to concatenating
         e#   the two lists).
         e#   Voilà, a list of all partitions of i.
}*
p        e# Pretty-print the result.

3

T-SQL,203个字节

打高尔夫球:

USE master
DECLARE @ INT=12

;WITH z as( SELECT top(@)cast(number+1as varchar(max))a FROM spt_values WHERE'P'=type),c as(SELECT a*1a,a b FROM z UNION ALL SELECT c.a+z.a,b+','+z.a FROM c,z WHERE c.a+z.a*1<=@)SELECT b FROM c WHERE a=@

取消高尔夫:

USE master --needed to make sure it is executed from the correct database
DECLARE @ INT=12

;WITH z as
(
  SELECT top(@)cast(number+1as varchar(max))a
  FROM spt_values
  WHERE'P'=type
),c as
(
  SELECT a*1a,a b
  FROM z
  UNION ALL
  SELECT c.a+z.a,b+','+z.a
  FROM c,z
  WHERE c.a+z.a*1<=@
)
SELECT b 
FROM c
WHERE a=@

小提琴


3

Mathematica 10.0,44个字节

尝试不使用与分区相关的内置函数。根据大小为k的每个有序分区,将生成k + 1的两个后续分区:一个通过在前面加上1,另一个通过在第一个值递增来进行。

Nest[##&[{1,##},{#+1,##2}]&@@@#&,{{1}},#-1]&

一个有趣的方法,但遗憾的是,实现相同想法的方法要长2个字节:

#@{1}&/@Tuples[Prepend[1]@*MapAt[#+1&,1],#-1]&

@alephalpha不,这无济于事,因为那时我不得不将MapAt索引更改为-1。
feersum

3

05AB1E14 12字节

感谢Adnan,节省了2个字节

>G¹LNãvyO¹Q—

说明

>G              # for N in range(1..input)
  ¹L            # range(1, input)
    Nã          # cartesian product with N (all combinations of length N)
      v         # for each resulting list
       yO¹Q—    # if it's sum equals the input print it

在线尝试!

相应的解决方案是2sable中短2个字节。

2sable,10字节

>GLNãvyOQ—

在线尝试!


您可以使用代替iy,:)。
阿德南

@Adnan:谢谢!忘了那个。
Emigna '16

3

Haskell,41个字节

f 1=[[1]]
f n=do a:b<-f$n-1;[1:a:b,a+1:b]

不是最短的Haskell解决方案,但我喜欢它不使用[..]范围。取而代之的是,它递归计算的分区,n作为的分区,n-1在开始时使用新的1或在第一个值较高时使用。这明确了为什么有2^(n-1)它们。


3

Mathematica,53个字节

没有击败马丁·恩德(Martin Ender)的答案,后者使用了内置IntegerPartitions功能(并且内置功能对我来说完全可以)。(也没有击败feersum的答案,直到很晚才出现。)但是我想练习高尔夫球递归函数。

If[#<1,{{}},Join@@Table[#~Append~j&/@#0[#-j],{j,#}]]&

通过生成所有可能的最终数字j,然后在输入的#-j位置进行调用,来递归地生成所有合成#


您可以通过使用Array而不是TableAppend通过使用列表来避免使用来定义运算符,从而节省一些字节Apply±0={{}};±n_:=Join@@Array[{##,n-+##}&@@@±#&,n,0]
Martin Ender

怎么@@办?
Cyoce's

它替换了表达式的“ head”。例如,f@@g[a,b]计算为f[a,b]。在这里,我们使用这样的事实:一个列表类似{ { {1,1,1}, {2,1} } , { {1,2} }, { {3} } }invisible都有head List;这样Join@@{ { {1,1,1}, {2,1} } , { {1,2} }, { {3} } }的计算结果为Join@@List[ { {1,1,1}, {2,1} } , { {1,2} }, { {3} } ]评估为Join[ { {1,1,1}, {2,1} } , { {1,2} }, { {3} } ]评估为{ {1,1,1}, {2,1}, {1,2}, {3} }
格雷格·马丁

3

视网膜,32字节

字节数假定为ISO 8859-1编码。

.+
$*
+%1`1
!$'¶$`,!
!+
$.&
A`^,

在线尝试!

说明

这类似于我的CJam答案。我们遍历一个列表N,然后在每个位置取二元决策的两个分支:a)增加最后一个值;或b)从1开始一个新值。

阶段1

.+
$*

将输入转换为一元。

第二阶段

+%1`1
!$'¶$`,!

+讲述视网膜的循环,直到输出停止变化来执行这个阶段。在%告诉它的输入应用阶段之前之后分割成线,并加入他们重新走到一起。通过将%+,Retina会在每次迭代后拆分并重新加入。该阶段的一次迭代做出了我提到的那些决定之一,从而将当前的一组分区分为两部分。

实际的工作方式是,它匹配一个1(但只有第一个,如1反引号前面的指示),然后替换为!(我们将其用作输出的一位数),然后是其余的1s。在此行上(这将增加最后一个值)。然后在另一行()上显示当前行的前缀,后跟,!,插入一个分隔符,然后在处开始下一个值1

第三阶段

!+
$.&

通过将!游程整数替换为十进制整数,将其转换为十进制整数。

阶段4

A`^,

最后,我们注意到我们生成的行数是我们想要的两倍,其中一半以a开头,(这些行是我们最初决定拆分的,即使之后没有拆分的内容)。因此,我们丢弃所有以开头的行,


3

Perl,44个字节

包括+3(用于-n代码用途$'$0因此不能作为-e命令行运行)

在STDIN上给分区编号:

partitions.pl <<< 4

partitions.pl

#!/usr/bin/perl -n
$_=$&-$_.",$_$'",do$0for/\d+/..$&-1;print

如果您不介意行尾和换行符之间有多余的空格,则此42字节的解决方案也可以使用(运行为perl -M5.010 partitions.pl):

#!/usr/bin/perl -n
$_=$`-$_." $_ $'",do$0for/\s/..$_-1;say

3

朱莉娅113字节

f(N)=unique(reduce(vcat,(map(x->[permutations(x)...],[vcat([1 for _=i+1:N],sum([1 for _=N-i:N-1])) for i=1:N]))))

非递归解决方案

解释:

  1. [vcat([1 for _=i+1:N],sum([1 for _=N-i:N-1])) for i=1:N] 建立一组总计为N的列表,其排列将类似于解决方案(例如,对于N = 4:[[1,1,1,1],[1,1,2],[1,3],[4 ]])
  2. map(x->[permutations(x)...],) 计算所有排列
  3. reduce(vcat,) 将它们合并为列表列表
  4. unique() 过滤重复项

我们要求提交的内容必须是完整的程序或功能,因此在这种情况下,您必须将其N作为输入。您可以通过添加N->3个字节作为前缀来制作lambda函数。
Alex A.

@AlexA。啊,很抱歉f(N)=在复制时迷路了,我在计数字节时就把它
弄丢了

2

MATL,15字节

:"G:@Z^t!XsG=Y)

在线尝试!

说明

在给定输入的情况下n,这会计算k1到的指数递增的笛卡尔乘方n。对于每个指数,k选择总和等于输入的元组。

:       % Take input n implicitly and push range [1 2 ... n]
"       % For each k in that range
  G:    %   Push [1 2 ... n] again
  @     %   Push k
  Z^    %   Cartesian power. Gives 2D array, say A, with each k-tuple in a row.
  t     %   Duplicate
  !     %   Transpose
  Xs    %   Sum of each column. Gives a row vector
  G=    %   True for entries that equal the input
  Y)    %   Use as logical vector into the rows of array A
        % End implicitly
        % Display stack implicitly

1

LUA 214 203 182字节

function g(m, l, n,c)for i=1,m do if i+n < m then l[#l+1]=i;g(m,l,n+i,c+1)elseif i+n == m then l[#l+1]=i;print(unpack(l))end end for k=c,#l do l[k]=nil end end g(io.read()*1,{},0,0)

取消版本。

function g(m, l, n,c)
    for i=1,m do 
        if i+n < m then 
            l[#l+1]=i
            g(m,l,n+i,c+1)
        elseif i+n == m then 
            l[#l+1]=i
            print(unpack(l))
        end 
    end 
    for k=c,#l do 
        l[k]=nil 
    end 
end 
g(io.read()*1,{},0,0)

找到了一个空白的空格,并删除了一个不必要的变量,将其保留为安全的11个字节。事实证明,table.insert()字节效率低


1

PHP,125字节

for($i=$n=$argv[1];$i<=str_repeat(1,$n);$i++)if(array_sum($a=str_split($i))==$n&!strpos($i,"0"))$r[]=$a;echo json_encode($r);

-4个字节print_r($r);代替echo json_encode($r);输出

250字节的递归解决方案

function f($n){global$a;foreach($a as$x)foreach(range(1,$n)as$y)$a[]=array_merge((array)$x,[$y]);if(--$n)f($n);}$a=range(1,$w=$argv[1]);f($w-1);foreach($a as$z)if(array_sum((array)$z)==$w)$c[join("-",(array)$z)]=$z;echo json_encode(array_values($c));

1

Prolog,81个字节+ 6个字节可调用

L*L.
[H|T]*L:-H>1,M is H-1,[M,1|T]*L.
[H,K|T]*L:-H>1,M is H-1,N is K+1,[M,N|T]*L.

在线尝试!
致电[4]*L.,重复为;直到提出所有解决方案为止。

或者,如果反复按;也不行(或应将其添加到字节数中),则调用bagof(L,[4]*L,M).将为该调用添加17个字节。


1

J30 26字节

#&1<@(+/;.1)~2#:@(+i.)@^<:

通过使用2 n的二进制值拆分一元n的列表来工作。

在线尝试!

说明

#&1<@(+/;.1)~2#:@(+i.)@^<:  Input: n
                        <:  Decrement n
             2         ^    Compute 2^(n-1)
                 (   )@     Operate on that
                   i.         Make the range [0, 1, ..., 2^(n-1)-1]
                  +           Add 2^(n-1) to each in that range
              #:@           Convert each in that range to binary
#&1                         Make n copies of 1 (n in unary)
     (     )~               Operate over each row on RHS and unary n on LHS
        ;.1                   Chop unary n starting at each 1
      +/                        Reduce by addition on each chop
   <@                           Box the sums of each chop

0

其实17 16字节

该答案部分基于Luis Mendo的MATL答案。欢迎打高尔夫球。在线尝试!

;╗R`╜R∙i`M`Σ╜=`░

开球

         Implicit input n.
;╗       Duplicate n and save a copy of n to register 0.
R        Take the range of [1..n].
`...`M   Map the following function over the range. Variable k.
  ╛R       Push n from register 0 and take the range [1..n] again.
  ∙        Take the k-th Cartesian power of the range.
  i        Flatten that product.
`...`░   Push values of the previous map where the following function returns a truthy value.
          Variable L.
  Σ        Push sum(L).
  ╜        Push n from register 0.
  =        Check if sum(L) == n.
         Implicit return.

0

其实17 16 15位元组

这是Martin Ender的CJam答案(带有笛卡尔积的答案)的一个有趣的分支,但在实现上的差异令我觉得很有趣。当Martin的字符串之一以增量开头时,错误将阻止对该字符串进行求值。实际上,该错误得到了抑制,并且无论如何都要对字符串进行求值。最终给出了k该范围内的每种成分[1..n]

我没有尝试删除多余的成分,而是采用了n-1笛卡尔函数,在每个字符串的开头都"1u"附加了a "1"。此技巧仅提供的组成n。不幸的是,它比马丁的答案更长。

欢迎打高尔夫球。在线尝试!

D"1u"∙`1@Σ£ƒk`M

开球

         Implicit input n.
D        Decrement n.
"1u"∙    Take the (n-1)th Cartesian power of the string "1u".
          In Actually, 1 pushes 1 to the stack and u is increment.
`...`M   Map the following function over the Cartesian power. Variable s.
  1@       Push a 1 to be used later.
  Σ        Summing a list of chars joins the chars into one string.
  £ƒ       Turn s into a function and call it immediately on the 1 in the stack.
  k        Take the whole stack and wrap in a list. This is a composition of n.
         Implicit return.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.