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?
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.
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']]
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.
Simply delete this part:
if len(original_list) % 2 != 0:
nested_list[-2].append(nested_list[-1][0])
nested_list.pop()
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?
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.
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']]
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.
Simply delete this part:
if len(original_list) % 2 != 0:
nested_list[-2].append(nested_list[-1][0])
nested_list.pop()