16
\$\begingroup\$

Given a list of integers L, and an integer N, output L splitted in N sublists of equal lenghts.

Non-divisible lengths

If N does not divide the length of L, then it is not possible that all sublists have equal length.

In any case, the last sublist of the output is the one that adapts its length to contain the remainder of the list.

This means that all sublists of L except for the last one should be of length length(L) // N, where // is floored division (e.g. 3//2 = 1).

Some rules

  • L can be empty.

  • N >= 1.

  • You may use any built-in you want.

  • You may take the input through STDIN, as a function argument, or anything similar.

  • You may print the output to STDOUT, return it from a function, or anything similar.

  • You may chose any format for the lists and the integer as long as it is the most natural representation of lists and integers in your language.

Test cases

Input:  [1,2,3,4], 2
Output: [[1,2],[3,4]]

Input:  [-1,-2,3,4,-5], 2
Output: [[-1,-2],[3,4,-5]]

Input:  [1,2,3,4], 1
Output: [[1,2,3,4]]

Input:  [4,8,15,16,23,42], 5
Output: [[4],[8],[15],[16],[23,42]]

Input:  [4,8,15,16,23,42], 7
Output: [[],[],[],[],[],[],[4,8,15,16,23,42]]

Input:  [2,3,5,7,11,13,17,19,23], 3
Output: [[2,3,5],[7,11,13],[17,19,23]]

Input:  [], 3
Output: [[],[],[]]

Input:  [1,2,3,4,5,6,7,8], 3
Output: [[1,2],[3,4],[5,6,7,8]]

Scoring

This is , so the shortest answer in bytes wins.

\$\endgroup\$
5
  • \$\begingroup\$ Related \$\endgroup\$
    – Fatalize
    Commented Jun 7, 2016 at 7:15
  • \$\begingroup\$ Also related \$\endgroup\$
    – Sp3000
    Commented Jun 7, 2016 at 7:57
  • \$\begingroup\$ Only positive integers? Or maybe add a test case \$\endgroup\$
    – Luis Mendo
    Commented Jun 7, 2016 at 9:53
  • \$\begingroup\$ @LuisMendo No. I changed a test case to reflect that. \$\endgroup\$
    – Fatalize
    Commented Jun 7, 2016 at 9:54
  • \$\begingroup\$ A list of length 8 with length n=3 (suggested by user2357112) would be a good test case -- it broke my method. \$\endgroup\$
    – xnor
    Commented Jun 7, 2016 at 23:54

14 Answers 14

4
\$\begingroup\$

Pyth, 11 10 bytes

1 byte thanks to @FryAmTheEggman.

cJEt*R/lJQ

Test suite.

Takes inputs in reversed order.

Sample input:

5
[1,2,3,4,5,6,7]

Sample output:

[[1], [2], [3], [4], [5, 6, 7]]

Explanation

cJEt*R/lJQ     Main function, first input:Q, second input:E.
cJEt*R/lJQQ    Implicit arguments.

c              The function c is special.
               It can chop arrays.
               If the second argument is a list of integers,
               then it chops the first array at the indices
               specified by the second array.

 JE            The first argument is the second input, stored
               to the variable J.

   t*R/lJQQ    This is the second argument.
      /lJQ     Yield length of J, integer-divided by Q.
    *R    Q    Multiply it to the following respectively:
                   [0,1,2,3,...,Q-1]
   t           Then throw away the first element.
               For example, if Q=3 and E=[1,2,3,4,5,6,7,8],
               we would now have [3,6].
\$\endgroup\$
0
4
\$\begingroup\$

JavaScript (ES6), 63 bytes

(a,n,l=a.length/n|0)=>[...Array(n)].map(_=>--n?a.splice(0,l):a)
\$\endgroup\$
3
\$\begingroup\$

K (ngn/k), 18 17 bytes

-1 thanks to @coltim

{*[!y;(-y)!#x]_x}

Try it online!

\$\endgroup\$
3
  • \$\begingroup\$ Can trim a byte by using the M-expression form of *, i.e. {*[!y;(-y)!#x]_x} \$\endgroup\$
    – coltim
    Commented Nov 9, 2023 at 14:07
  • \$\begingroup\$ @coltim Do you have a link to or explanation of M-expressions? \$\endgroup\$
    – Jonah
    Commented Nov 9, 2023 at 15:34
  • 2
    \$\begingroup\$ It's taken from (early) lisp, per en.wikipedia.org/wiki/M-expression . basically, x*y is equivalent to *[x;y] (the brackets bind tightly). it's also how K handles calling functions with more than two args, e.g. f4[a;b;c;d]. \$\endgroup\$
    – coltim
    Commented Nov 9, 2023 at 20:27
2
\$\begingroup\$

Python, 76 73 bytes

lambda L,N:list(map(lambda x,r=len(L)//N:L[x*r:][:r+(x>N-2)*N],range(N)))

Basically an unnamed function that performs the task. Thanks to LeakyNun for the bytes saved!

\$\endgroup\$
7
  • 1
    \$\begingroup\$ Also, welcome to PPCG! \$\endgroup\$
    – Leaky Nun
    Commented Jun 7, 2016 at 8:15
  • \$\begingroup\$ @LeakyNun Nun It's 73 I think actually. Also it's mostly my fault as I wasn't paying much attention while editing. Perils of codegolfing at work :P \$\endgroup\$
    – Lause
    Commented Jun 7, 2016 at 8:45
  • \$\begingroup\$ @LeakyNun - to the first point - it doesn't work. The expression basically is [:r] for regular items and [:r+N] for the last item, which is supposed to catch all the remaining elements. The second point - I tried but all the ways I know that let me assign r make it longer than my code. \$\endgroup\$
    – Lause
    Commented Jun 7, 2016 at 10:31
  • \$\begingroup\$ It would, but in the case of r*(x>N-2) it's [:0] , not [:]. \$\endgroup\$
    – Lause
    Commented Jun 7, 2016 at 11:21
  • \$\begingroup\$ Well, here \$\endgroup\$
    – Leaky Nun
    Commented Jun 7, 2016 at 12:21
2
\$\begingroup\$

Common Lisp, 114 bytes

(defun f(l n &optional(p(floor(length l)n))(i 1))(if(= i n)(list l)(cons(subseq l 0 p)(f(subseq l p)n p(+ i 1)))))

Ungolfed:

(defun f (l n &optional (p (floor (length l) n)) (i 1))
  (if (= i n) (list l)
              (cons (subseq l 0 p)
                    (f (subseq l p) n p (+ i 1))))
  )

Example call:

(format t "~A~C~C" (f (read) (read)) #\return #\newline)

Try it here!

Basically:

  • If we are cutting the last group, return whatever's left of the initial list.
  • Otherwise take p = |L| / N elements out of the list and join that to the result of a recursive call on the remainder. i is an iteration counter used for the stop condition.

I had misunderstood the challenge at first, thinking the program should build groups of N elements rather than N groups. Anyway, this version does the job for an extra 10 bytes. LisP won't win this time but I couldn't really miss the opportunity :')

\$\endgroup\$
2
\$\begingroup\$

Haskell, 69 67 bytes

a%b=a#b where l#1=[l];l#n|(h,t)<-splitAt(div(length a)b)l=h:t#(n-1)

Usage example: [1,2,3,4] % 3 -> [[1],[2],[3,4]].

A simple recursive approach, similar to @xnor's answer.

Edit: @Will Ness saved 2 bytes. Thanks!

\$\endgroup\$
1
  • \$\begingroup\$ h:t#(n-1) also works. \$\endgroup\$
    – Will Ness
    Commented Jun 7, 2016 at 23:22
2
\$\begingroup\$

Vyxal, 67 bitsv2, 8.375 bytes

L>ßwṘÞ÷RṘ

Try it Online!

Bitstring:

0110000000101110001001111010001000011101011000101111111101011010001
\$\endgroup\$
2
\$\begingroup\$

J, 34 bytes

](],#@;@]<@}.[)<:@[{.-@(<.@%~#)<\]

Try it online!

This was way harder than it should have been, and I threw away two approaches before getting this, which still feels long.

  • (<.@%~#) Integer divide list size by n. This will be the "regular" bucket size (ie, the size of buckets which are not the final, variable bucket).
  • -@...<\] Break up the list into buckets of those size. This will result in an extra bucket when the list is not evenly divisible.
  • <:@[{. From that list of buckets, take one less than n. This many buckets are guaranteed to be the regular size. Note that if size of the original list is less than n, these regular buckets will have size 0.
  • (],#@;@]<@}.[) To these regular elements append ], all the remaining elements #@;@]<@}.[. That is, if there are r regular elements, kill the first r elements of the original list and put everything that remains into a single bucket. That is the final bucket which we'll append to the regular buckets. In the case of an evenly divisible list, it will be just one more regular element. Otherwise it will be a final jumbo element.

J, 34 bytes, K answer port (ish)

-@[{.]<;.1~i.@#@]<@e.i.@[*(<.@%~#)

Try it online!

bstrat's K answer inspired me to revisit an earlier approach of mine, which at a high-level was almost identical.

The difference in length between the J and K answers highlights interesting differences between K's cut primitive (which specifies cut points by indexes) and J's (which requires a boolean array where ones specify cut points). The J approach fares quite poorly in this problem, and requires additional post processing to make the empty cells match the problem specification.

Another approach I tried was using J's "remove the fret points" cut option to get the empty cells correct in a natural way, but doing this requires you to duplicate the fret points just-so, and thus incurs a heavy pre-processing cost.

\$\endgroup\$
2
\$\begingroup\$

J, 29 bytes

-@[{.(I.@(<.@%~+-@[{.|)#)</.]

Attempt This Online!

-2 thanks to Jonah for noticing that </. (grouping) followed by -@[{. (add enough empty groups) works. Why it works with an empty vector input is a mystery...


J, 31 bytes

]<@#~i.@[=/(I.@(<.@%~+-@[{.|)#)

Attempt This Online!

After all sorts of approaches tried and thrown away, I finally settled with the one that creates a boolean matrix and gives the chunks via #. Most others suffered badly when the "regular buckets" are empty.

For the input of 3 and [1 2 3 4 5 6 7 8],

]<@#~i.@[=/(I.@(<.@%~+-@[{.|)#)
           (                 #)    call inner function with 3 and length of array (8):
               (<.@%~       )      size of regular bucket (2)
                           |       number of extra elements (2)
                      -@[{.        left-pad with zeros to the length of 3; [0 0 2]
                     +             elementwise add; [2 2 4]
            I.@    copy each index by the element; [0 0 1 1 2 2 2 2]
     i.@[          range of 3; [0 1 2]
         =/        outer product by equality;
                   [[1 1 0 0 0 0 0 0]
                    [0 0 1 1 0 0 0 0]
                    [0 0 0 0 1 1 1 1]]
]<@#~    for each row of the above, keep places corresponding to 1s;
         {[1 2] [3 4] [5 6 7 8]}

If I don't need to handle the cases where empty buckets are present, i.@[=/ can be golfed to =@.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Using the boolean matrix to group is cool but you can actually take just the right part of your answer with a normal /. for 29: -@[{.(I.@(<.@%~+-@[{.|)#)</.]. It's weird I thought I had tried that myself but must not have landed on that exact phrasing. I think <.@%~+-@[{.| is a bit golfier than what I must have had. \$\endgroup\$
    – Jonah
    Commented Nov 10, 2023 at 18:09
1
\$\begingroup\$

PowerShell v2+, 125 bytes

param($l,$n)if($p=[math]::Floor(($c=$l.count)/$n)){1..$n|%{$l[(($_-1)*$p)..((($_*$p-1),$c)[!($_-$n)])]}}else{(,''*($n-1))+$l}

Feels too long, but I can't seem to come up with a way to get the slicing to work happily if there are empty arrays in the output, so I need the encapsulating if/else to handle those cases. Additionally, since PowerShell's default .ToString() for arrays via console output can look a little weird, you can tack on a -join',' to show the arrays as comma-separated rather than newline-separated on the console. I've done that in the examples below to make the output more clear, but you won't want to do that if you're leaving the output on the pipeline for another command to pick up.

Explanation

Takes input param($l,$n) for the list and number of partitions, respectively. We then enter an if/else statement. If the size of each partition, $p is non-zero (setting helper $c to be the .count along the way), we're in the if.

Inside the if, we loop from 1 to $n with |%{...}, and each iteration we're doing a pretty complex-looking array slice $l[(($_-1)*$p)..((($_*$p-1),$c)[!($_-$n)])]. The first parens is our start index, based on what partition we're on and how big our partition size is. We range that .. with our end index, which is formed from a pseudo-ternary. Here, we're choosing between either $c (the literal end of the array), or the length of our partition, based on whether we're in the last chunk $_-$n or not.

Otherwise, we're in the else. We construct an empty array with the comma-operator ,''* equal to one fewer partitions than requested, and then tack on the input array as the final element.

Examples

Here I'm showing the partitions separated with newlines and each individual element separated with ,, as described above.

PS C:\Tools\Scripts\golfing> .\n-chotomize-a-list.ps1 (1,2,3,4) 2
1,2
3,4

PS C:\Tools\Scripts\golfing> .\n-chotomize-a-list.ps1 (-1,-2,3,4,-5) 2
-1,-2
3,4,-5

PS C:\Tools\Scripts\golfing> .\n-chotomize-a-list.ps1 (1,2,3,4) 1
1,2,3,4

PS C:\Tools\Scripts\golfing> .\n-chotomize-a-list.ps1 (4,8,15,16,23,42) 5
4
8
15
16
23,42

PS C:\Tools\Scripts\golfing> .\n-chotomize-a-list.ps1 (4,8,15,16,23,42) 7






4,8,15,16,23,42

PS C:\Tools\Scripts\golfing> .\n-chotomize-a-list.ps1 (2,3,5,7,11,13,17,19,23) 3
2,3,5
7,11,13
17,19,23

PS C:\Tools\Scripts\golfing> .\n-chotomize-a-list.ps1 $null 3



PS C:\Tools\Scripts\golfing> 
\$\endgroup\$
1
\$\begingroup\$

F#, 100 98 bytes

fun n l->
let a=List.length l/n
List.init n (fun i->if i<n-1 then l.[a*i..a*i+a-1] else l.[a*i..])

Using F# list slicing, with an if clause deciding whether to pick a elements or all remaining elements.

\$\endgroup\$
1
\$\begingroup\$

Prolog, 100 99 bytes.

n(A,B):-length(B,A).
p(L,K,G):-n(K,G),append(A,[_],G),n(N,L),M is N//K,maplist(n(M),A),append(G,L).

Call e.g.

?- p( [1,2,3,4,5,6,7], 3, X).
X = [[1, 2], [3, 4], [5, 6, 7]] .

\$\endgroup\$
0
1
\$\begingroup\$

JavaScript (Node.js), 56 bytes

f=(a,n,l=a.length/n|0)=>[a,...--n?f(a.splice(l),n,l):[]]

Try it online!

\$\endgroup\$
0
\$\begingroup\$

PHP, 109 Bytes

<?for($n=(count($a=$_GET[0]))/($d=$_GET[1])^0;$i<$d;)$r[]=array_slice($a,$i*$n,++$i==$d?NULL:$n);print_r($r);

All Testcases

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.