How to turn list into nested in a specific way?

Question:

I have a list: ["a", "b", "c", "d", "e", "f", "g"]. I want to make it nested and put in sublists of two consecutive values ​​from the given list. if there are no two values ​​left, then one value should go to the sublist. so desired result is: [["a", "b"], ["c", "d"], ["e", "f"], ["g"]].

I tried this:

original_list = ["a", "b", "c", "d", "e", "f", "g"]
nested_list = []

for i in range(0, len(original_list), 2):
    sublist = original_list[i:i+2]
    nested_list.append(sublist)

if len(original_list) % 2 != 0:
    nested_list[-2].append(nested_list[-1][0])
    nested_list.pop()

print(nested_list)

and the output was correct: [['a', 'b'], ['c', 'd'], ['e', 'f', 'g']].

But for this example:

original_list = ["a", "b", "c"]
nested_list = []

for i in range(0, len(original_list), 2):
    sublist = original_list[i:i+2]
    nested_list.append(sublist)

if len(original_list) % 2 != 0:
    nested_list[-2].append(nested_list[-1][0])
    nested_list.pop()

print(nested_list)

the output is [['a', 'b', 'c']] instead of [['a', 'b'], ['c']]

How could i fix it?

Asked By: french_fries

||

Answers:

You can get most of the way there by using zip to pair every even element with a corresponding odd element (this is roughly the same as what the first half of your code does):

>>> original_list = ["a", "b", "c", "d", "e", "f", "g"]
>>> [list(pair) for pair in zip(original_list[::2], original_list[1::2])]
[['a', 'b'], ['c', 'd'], ['e', 'f']]

and then handle the last element (if the length of the overall list is odd) as a special case:

>>> nested_list = [list(pair) for pair in zip(original_list[::2], original_list[1::2])]
>>> if len(original_list) % 2:
...     nested_list.append([original_list[-1]])
...
>>> nested_list
[['a', 'b'], ['c', 'd'], ['e', 'f'], ['g']]

It’s also possible to construct the zip in such a way as to handle the odd case on its own (i.e. adding a dummy element to the end, or using zip_longest, and then accounting for that when building the list of pairs) but I think the above way is the simplest.

Answered By: Samwise

The zip / zip_longest approaches suggested by Samwise and Jorge are good, but you could also do this by simply iterating over original_list and handling each element as you encounter it.
First, initialize nested_list as a list containing an empty list.

nested_list = [[]]

As you iterate over original_list, check that the last element of nested_list contains less than two elements. If it doesn’t, append a new empty list to nested_list. If it does contain less than two elements (if it didn’t earlier, this is now true since you appended an empty list), append the current element to that list:

for item in original_list:
    if len(nested_list[-1]) >= 2:
        nested_list.append([])

    nested_list[-1].append(item)

Now, nested_list looks like the desired output:

[['a', 'b'], ['c', 'd'], ['e', 'f'], ['g']]
Answered By: Pranav Hosangadi

Just to write clearly how to use zip_longest as Samwise suggested:

from itertools import zip_longest


combined = zip_longest(original_list[::2], original_list[1::2])
# Avoid None elements in the last list
nested_list= [[element for element in pair if element]
              for pair in combined]

This method can be easily generalized as zip_longest can get as many arguments as you would like to iterate.

Answered By: Jorge Luis

Simply delete this part:

if len(original_list) % 2 != 0:
    nested_list[-2].append(nested_list[-1][0])
    nested_list.pop()
Answered By: Kelly Bundy
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.