Velocity Reviews > splitting a list into n groups

# splitting a list into n groups

Rajarshi Guha
Guest
Posts: n/a

 10-08-2003
Hi,
is there an efficient (pythonic) way in which I could split a list into
say 5 groups? By split I mean the the first x members would be one group,
the next x members another group and so on 5 times. (Obviously x =
lengthof list/5)

I have done this by a simple for loop and using indexes into the list.
But it does'nt seemm very elegant

Thanks,

Tim Hochberg
Guest
Posts: n/a

 10-08-2003
Rajarshi Guha wrote:
> Hi,
> is there an efficient (pythonic) way in which I could split a list into
> say 5 groups? By split I mean the the first x members would be one group,
> the next x members another group and so on 5 times. (Obviously x =
> lengthof list/5)
>
> I have done this by a simple for loop and using indexes into the list.
> But it does'nt seemm very elegant

Depending on what you're doing, this may or may not be appropriate, but
you might want to look at Numeric (or it's eventual successor numarray).
In this case, you could use reshape to map your list into a n by x
array, which you can treat like a nested list with respect to indexing.

>>> import Numeric
>>> data = range(25)
>>> split = Numeric.reshape(data, (5,5))
>>> split

array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
>>> split[0]

array([0, 1, 2, 3, 4])
>>> list(split[4])

[20, 21, 22, 23, 24]

You can sometimes use Numeric with nonnumeric data, but it tends to be
quircky and often is not worth the trouble, but if you've got numeric
data, try it out.

-tim

Eddie Corns
Guest
Posts: n/a

 10-08-2003
Rajarshi Guha <(E-Mail Removed)> writes:

>Hi,
> is there an efficient (pythonic) way in which I could split a list into
>say 5 groups? By split I mean the the first x members would be one group,
>the next x members another group and so on 5 times. (Obviously x =
>lengthof list/5)

How about:

------------------------------------------------------------
def span (x, n):
return range(0, x, n)

def group (l, num):
n = (len(l)/num) + 1
return [l[s:s+n] for s in span (len(l), n)]

# test cases
l1 = range(100)
print group (l1, 5)
print group (l1, 6)
print group (l1, 4)
------------------------------------------------------------

Even though span could be folded in to make it shorter, abstracting it out
allows you to name and document what it does (return the start index of each
SPAN of n items). Also it doesn't worry too much about the last list being
the same size as the rest. I'm too lazy to check the boundary conditions
properly (an exercise for the reader). A completely non lazy person would
possibly define the more primitive group_by_n:

def group_by_n (l, n):
return [l[s:s+n] for s in span (len(l), n)]

and define group_into_num_pieces in terms of that:

def group_into_num_pieces (l, num):
return group_by_n (l,(len(l)/num) + 1)

giving you 3 useful functions for the price of 1, but I'm too lazy for that.

Eddie

Terry Reedy
Guest
Posts: n/a

 10-08-2003

"Rajarshi Guha" <(E-Mail Removed)> wrote in message
newsan.2003.10.08.17.42.18.956301.22624@presiden cy.com...
> Hi,
> is there an efficient (pythonic) way in which I could split a list

into
> say 5 groups? By split I mean the the first x members would be one

group,
> the next x members another group and so on 5 times. (Obviously x =
> lengthof list/5)
>
> I have done this by a simple for loop and using indexes into the

list.
> But it does'nt seemm very elegant

Does it work correctly for all input cases? Is it readable? Is it
acceptibly fast? If so, it is probably 'Pythonic' enough.

TJR

Paul Rubin
Guest
Posts: n/a

 10-08-2003
Rajarshi Guha <(E-Mail Removed)> writes:
> is there an efficient (pythonic) way in which I could split a list into
> say 5 groups? By split I mean the the first x members would be one group,
> the next x members another group and so on 5 times. (Obviously x =
> lengthof list/5)

groups = [a[i:i+(len(a)//5)] for i in range(5)]

Peter Otten
Guest
Posts: n/a

 10-08-2003
Paul Rubin wrote:

> Rajarshi Guha <(E-Mail Removed)> writes:
>> is there an efficient (pythonic) way in which I could split a list into
>> say 5 groups? By split I mean the the first x members would be one group,
>> the next x members another group and so on 5 times. (Obviously x =
>> lengthof list/5)

>
> groups = [a[i:i+(len(a)//5)] for i in range(5)]

>>> for k in range(10):

.... a = range(k)
.... print [a[i:i+(len(a)//5)] for i in range(5)]
....
[[], [], [], [], []]
[[], [], [], [], []]
[[], [], [], [], []]
[[], [], [], [], []]
[[], [], [], [], []]
[[0], [1], [2], [3], [4]]
[[0], [1], [2], [3], [4]]
[[0], [1], [2], [3], [4]]
[[0], [1], [2], [3], [4]]
[[0], [1], [2], [3], [4]]
>>>

Is that what you expected?

Peter

Peter Otten
Guest
Posts: n/a

 10-08-2003
Eddie Corns wrote:

> Rajarshi Guha <(E-Mail Removed)> writes:
>
>>Hi,
>> is there an efficient (pythonic) way in which I could split a list into
>>say 5 groups? By split I mean the the first x members would be one group,
>>the next x members another group and so on 5 times. (Obviously x =
>>lengthof list/5)

>
> How about:
>
> ------------------------------------------------------------
> def span (x, n):
> return range(0, x, n)
>
> def group (l, num):
> n = (len(l)/num) + 1
> return [l[s:s+n] for s in span (len(l), n)]
>
> # test cases
> l1 = range(100)
> print group (l1, 5)
> print group (l1, 6)
> print group (l1, 4)
> ------------------------------------------------------------

More test cases

for k in range(20):
l1 = range(k)
lol = group(l1, 5)
print len(lol), lol

0 []
1 [[0]]
2 [[0], [1]]
3 [[0], [1], [2]]
4 [[0], [1], [2], [3]]
3 [[0, 1], [2, 3], [4]]
3 [[0, 1], [2, 3], [4, 5]]
4 [[0, 1], [2, 3], [4, 5], [6]]
4 [[0, 1], [2, 3], [4, 5], [6, 7]]
5 [[0, 1], [2, 3], [4, 5], [6, 7], [8]]
4 [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
4 [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]
4 [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]
5 [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12]]
5 [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13]]
4 [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14]]
4 [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]
5 [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15], [16]]
5 [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15], [16, 17]]
5 [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15], [16, 17,
18]]

Peter

Paul Rubin
Guest
Posts: n/a

 10-08-2003
Peter Otten <(E-Mail Removed)> writes:
> > groups = [a[i:i+(len(a)//5)] for i in range(5)]

>
>
> >>> for k in range(10):

> ... a = range(k)
> ... print [a[i:i+(len(a)//5)] for i in range(5)]
> ...
> [[], [], [], [], []]

....
> Is that what you expected?

Bah! Nope, got confused and mis-wrote the loop contents (started
thinking of donig it one way, then another, then got the two mixed up
while typing). Also, wasn't concerned about the case where the list
can't be chopped into equal length parts. Try this:

assert len(a) > 0 and len(a) % 5 == 0
d = len(a) // 5
groups = [a[d*i:d*(i+1)] for i in range(5)]

Handling the case where the pieces end up unequal because len(a) isn't
a multiple of 5 gets a little messy:

d = (len(a) + 4) // 5
groups = [a[d*i:d*(i+1)] for i in range(5)]

when a = range(6) gives

[[0, 1], [2, 3], [4, 5], [], []]

It's not clear to me whether that's good or bad: something like

[[0, 1], [2], [3], [4], [5]]

is probably better, but that would depend on the application.

Cousin Stanley
Guest
Posts: n/a

 10-08-2003
| ....
| More test cases
| ....

Peter ....

I use Outlook Express with the Quote-Fix add on
for reading news groups and got quite a chuckle
when I saw how your test-case code showed up here ....

http://fastq.com/~sckitching/Python/python_lol.png
[ 2 KB ]

--
Cousin Stanley
Human Being
Phoenix, Arizona

Corey Coughlin
Guest
Posts: n/a

 10-08-2003
Rajarshi Guha <(E-Mail Removed)> wrote in message news:<pan.2003.10.08.17.42.18.956301.22624@preside ncy.com>...
> Hi,
> is there an efficient (pythonic) way in which I could split a list into
> say 5 groups? By split I mean the the first x members would be one group,
> the next x members another group and so on 5 times. (Obviously x =
> lengthof list/5)
>
> I have done this by a simple for loop and using indexes into the list.
> But it does'nt seemm very elegant
>
> Thanks,

I had the same problem a while back. Here's the function I wrote:

def GroupList(inlist, step=2):
outlist = []
ents = len(inlist)
if ents % step != 0:
print "In GroupList, the length of list ", inlist, " isn't
evenly"
print "divisible by step %i" % step
sys.exit(4)
maininds = filter(lambda x: x % step == 0, range(ents))
for i in maininds:
currlist = []
for j in range(step):
currlist.append(inlist[i+j])
outlist.append(currlist)
return outlist

As you can see, I made some assumptions (the default n is 2, the list
must be evenly divisible by the step, and so on) and I haven't heavily
debugged it, but it might help you out.

 Thread Tools

 Posting Rules You may not post new threads You may not post replies You may not post attachments You may not edit your posts BB code is On Smilies are On [IMG] code is On HTML code is OffTrackbacks are On Pingbacks are On Refbacks are Off Forum Rules

 Similar Threads Thread Thread Starter Forum Replies Last Post lemon97@gmail.com Python 12 08-08-2005 10:29 PM Piet Python 3 06-02-2004 09:59 PM John Dibling C++ 0 07-19-2003 04:41 PM Mark C++ 0 07-19-2003 04:24 PM John Ericson C++ 0 07-19-2003 04:03 PM

Advertisments