0

I have a nested list in the following form

inputlist = [[1,2,3],[4,5,6],[7,8,9],[1,2,3,4],[5,6,7,8],[1,2],[3,4]]

I would like further nest it based on changing length as follows:

outputlist = [[[1,2,3],[4,5,6],[7,8,9]],[[1,2,3,4],[5,6,7,8]],[[1,2],[3,4]]]

The underlying logic is that I wish to group every change in list length into a new sublist. It is kind of difficult to explain but I hope the above two examples show what I am trying to do.

How can I achieve this simply and elegantly using python? Thanks.

user32882
  • 5,094
  • 5
  • 43
  • 82
  • 2
    What have you tried so far? Please post your code. – James Feb 09 '18 at 12:56
  • The code is really long and based on a native file type that we use. The underlying idea is that I wish to detect changes in line lengths in this filetype. Currently I am doing it by reading the file, looping through the lines, mapping lines to lists then keeping track of which is the current line and previous line, doing comparisons and appending empty lists from these comparisons. The issue is that the whole problem boils down to the above simple problem. I will try to make some new attempts and post them above. – user32882 Feb 09 '18 at 12:59
  • Possible "duplicate" of https://stackoverflow.com/questions/773/how-do-i-use-pythons-itertools-groupby – mkrieger1 Feb 09 '18 at 13:06
  • I don't agree. That's a general question about how to use itertools.groupby. We also have a valid answer below which doesn't mention the use of itertools. I really think this question is OK – user32882 Feb 09 '18 at 13:11
  • 1
    @user32882 It isn't a duplicate since it's specific about nested list grouping by length, but `itertools` `groupby` is definitely the recommended approach – jamylak Feb 09 '18 at 13:15
  • I certainly agree. I did vote up the other answer though for effort – user32882 Feb 09 '18 at 13:17

2 Answers2

4
>>> from itertools import groupby
>>> input_list = [[1,2,3],[4,5,6],[7,8,9],[1,2,3,4],[5,6,7,8],[1,2],[3,4]]
>>> [list(g) for k, g in groupby(input_list, key=len)]
[[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[1, 2, 3, 4], [5, 6, 7, 8]], [[1, 2], [3, 4]]]
jamylak
  • 128,818
  • 30
  • 231
  • 230
0

Here's an approach.

Get a list of the lengths involved:

#solen: set of lengths
solen = set([len(subl) for subl in inputlist])   # portable
solen = {len[subl] for subl in inputlist}        # post Python 2.6

Then build the list of lists of a particular length:

#losubl: list of sublists, one for each item from solen
losubl = [[subl for subl in inputlist if len(subl) == ulen] for ulen in solen]

As jamylak points out, this solution is less efficient than the one based on itertools (more than one pass, sacrifices some order information). OTOH, it may avoid an import if you don't have other uses for itertools. If the lists you're working with are big and complicated, it's probably worth the extra import to use itertools.

Tom Barron
  • 1,554
  • 18
  • 23
  • 1
    this requires traversing multiple times and loses order. also using `l` as variable name is not recommended in PEP8 – jamylak Feb 09 '18 at 13:11
  • 1
    also if you were gonna do `set([len(x) for x in inputlist])`, a nicer way since Python 2.6 is `{len(x) for x in inputlist}` – jamylak Feb 09 '18 at 13:14
  • @jamylak: I'm editing my answer to account for your suggestions. Is there a difference between '... for x in ]' and '... for l in ]'? Why did you call out the single character iteration variable 'l' but not 'x'? – Tom Barron Feb 09 '18 at 13:48
  • `l` is hard to distinguish from `1` and `I` – jamylak Feb 09 '18 at 13:49
  • @jamylak: Thanks – Tom Barron Feb 09 '18 at 13:51