0

I have a list that needs to be split into 4 separate lists with maximum size of 21 depending on the amount of items in the original list.

The master list can have from 1 to 84 items.

I want the items to start in a and fill up to a maximum of 21 in a, b, c, d

I have the following code that can split the items up no problem but I want to know if there is a shorter way to do this. I am repeating code a lot except the range.

codes = [x for x in range(80)] # range anywhere between 1-84

print(len(codes))

a = []
b = []
c = []
d = []

for i in range(0, 21):
    try:
        a.append(codes[i])
    except IndexError:
        pass

for i in range(21, 42):
    try:
        b.append(codes[i])
    except IndexError:
        pass

for i in range(42, 63):
    try:
        c.append(codes[i])
    except IndexError:
        pass

for i in range(63, 84):
    try:
        d.append(codes[i])
    except IndexError:
        pass

print(len(a), len(b), len(c), len(d))
print(a)
print(b)
print(c)
print(d)

Before that I had this code that works great for the whole 84 items as the order is not important..

    a = []
    b = []
    c = []
    d = []

    for a1, b1, c1, d1 in zip(*[iter(codes)]*4):
        a.append(a1)
        b.append(b1)
        c.append(c1)
        d.append(d1)

However if i have say 4 items, it will add 1 to each

a = [0]
b = [1]
c = [2]
d = [3]

What I would like to obtain is

a = [0, 1, 2, 3]
b = []
c = []
d = []
wuarmin
  • 3,274
  • 3
  • 18
  • 31
johnashu
  • 2,167
  • 4
  • 19
  • 44
  • 2
    Possible duplicate of [How do you split a list into evenly sized chunks?](https://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks) – Julian Camilleri Sep 03 '18 at 07:53

6 Answers6

4

You can simply use sublist

a = codes[0: 21]
b = codes[21:42]
c = codes[42:63]
d = codes[63:84]

This will be fine for your requirement

  • 1
    I think, that's the most *pythonic* way to do it! Plain and simple. It's code like this that makes me love Python! – winklerrr Aug 31 '18 at 09:47
4

@SajalPreetSinghs answer is correct for a simple use case like OP's but it also has some disadvantages when it comes to scalability.

For example:

  • When you need 20 sublists instead of the actual 4. You would have to add 16 more lines and specify 2 different numbers per line each!
  • Now imagine you already extended the code to 20 sublists but now you want the maximum item count per sublist to be 37 instead of 21 - you would have to change 2*20 = 40 numbers!

Improved scalability with generators

So if you want something with a better scalability you could use the following code which makes usage of generators:

Code

def sublist(orig_list, list_of_subs, max_items_per_list):
    def sublist_generator():
        for sublist in list_of_subs:
            yield sublist

    sublist = sublist_generator()
    current_sublist = next(sublist)
    for element in orig_list:
        current_sublist.append(element)

        if len(current_sublist) == max_items_per_list: # current list is full
            current_sublist = next(sublist) # so let current point to the next list

Setup and usage

import random
start = 1
stop = random.randint(2, 85) # generate random int inclusively 2 and 85
codes = [x for x in range(start, stop)] # stop is exclusive: range(1, 85) == [1, 2, ..., 84]

a, b, c, d = [], [], [], []
sublists = [a, b, c, d] # *1

sublist(codes, sublists, 21)
for sublist in sublists:
    print(sublist)

Better scalability because

  • If you want to change the number of items per sublist you only have to pass in the new maximum number.

  • If you want to increase the number of sublists you only have to add more of them to the sublists variable which you pass to the function (see *1).

  • If you need this code more often it's no problem because you can comfortably call the function.

I hope this helps someone!

Cheers
winklerrr

winklerrr
  • 13,026
  • 8
  • 71
  • 88
  • 1
    For my use case the answer was perfect but my use was very specific and I wanted to avoid adding a lot of unnecessary code to an already large base. That being said this is a perfect and elegant solution for scaling and reuse. I for one have this function saved and I hope more people can find it useful! – johnashu Aug 31 '18 at 16:28
  • This answer is much better than the one selected since this one can be scaled easily to any use case with any number of sublists as needed. – typedecker Mar 28 '21 at 13:26
  • I'd change the last four lines in the code to prevent an error if your orig_list fits exactly in the sublists (eg. 40 elements in 4 lists of 10) for i, element in enumerate(orig_list): current_sublist.append(element) if len(current_sublist) == max_items_per_list and (i != len(orig_list)-1): # current list is full and we are not at the end current_sublist = next(sublist) – Rene Smit Jul 19 '21 at 22:33
3

You can do it with using a list comprehension:

MAX_SIZE = 21

l = list(range(80))

l1,l2,l3,l4 = [l[i*MAX_SIZE: (i+1)*MAX_SIZE] for i in range(4)] 


#l1=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,20],
# .... 
#l4=[63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79]
abc
  • 11,579
  • 2
  • 26
  • 51
3

You could use the zip_longest function from itertools

from itertools import zip_longest

master_list = range(0, 84)

iterables = [iter(master_list)] * 21
slices = zip_longest(*iterables, fillvalue=None)

for slice in slices:
    print("slice", slice)

# slice (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20)
# slice (21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41)
# slice (42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62)
# slice (63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83)
wuarmin
  • 3,274
  • 3
  • 18
  • 31
  • How can I split them into 4 lists of max length 21? It prints but when i try to append, it adds everything to each list – johnashu Aug 31 '18 at 09:20
  • 2
    Ah, this works as well as the accepted answer!. Thank you for the effort. I have learnt something new here – johnashu Aug 31 '18 at 09:45
  • in case you want lists without None, the use `list(filter(None, slice))` – Nim J Feb 11 '21 at 10:18
1

What I would do would be just put it in one loop.

if index is 0 to 83

for i in range(0,84):

   if i>=0 and i<=20:
      a.append(codes[i])
   elif i>20 and i<=41:
      b.append(codes[i])
   elif i>41 and i<=62:
      c.append(codes[i])
   elif i>62 and i<=83:
      d.append(codes[i])
Jessica Dionisio
  • 151
  • 1
  • 1
  • 7
  • This only works if the master list is exactly 84 in len otherwise it will throw an `IndexError`.. the range has to be anywhere between 1-84.. – johnashu Aug 31 '18 at 08:59
  • I'm assuming a list starts an index 0 that's why i said 0-83 which is exactly just the same. Oh and sorry, i'm assuming that your master list is always 84, but we can improve this code then to make it dynamic. But much better answers are given. Thanks tho! – Jessica Dionisio Aug 31 '18 at 16:19
1

A solution using a list comprehension:


i_list = range(0,84)
r = 21
res = [i_list[i:i+r] for i in range(0,len(i_list),r)]
TigerTV.ru
  • 1,058
  • 2
  • 16
  • 34