I have a problem with dealing with elements in a list. To be precise in a list of lists. For example, I have list of elements that are read from a file:
list_1 = [['void', None], ['uint8', 'f_MbistTestType_u8'], ['uint8', 'uint32', 'f_MbistTestType_u8', 'f_chip_id_u32'], ['void', None], ['void', None], ['void', None], ['void', None]]
In this case third element has more than two elements. I want to switch element 2 with element 3. So it would look like this:
list_1[2] = ['uint8', 'f_MbistTestType_u8', 'uint32', 'f_chip_id_u32']
If there would be 6 elements i.e.
list_example = ['uint8', 'uint32', 'void', 'f_chip_id_u32', 'f_MbistTestType_u8', None]
After the operation it should look like this:
list_example_sorted = ['uint8', 'f_chip_id_u32', 'uint32', 'f_MbistTestType_u8', 'void', None]
Right now I know how to get those elements in case I have only one occurrence of more than 2 elements, but don't know how to switch their places and also what to do in case I have more than one occurrence:
for elements in list_1:
print(elements)
if len(elements) > 2:
list_el = elements
print(list_el)
I tried to pop them out and append, but it won't scale well with more than 4 elements.
I tried to use swap function, but it seems that it doesn't work or I used it wrong?
CodePudding user response:
Going by an input of [1, 1, 1, 2, 2, 2]
with the desired output [1, 2, 1, 2, 1, 2]
, i.e. you want the first element of the left half followed by the first element of the right half and so forth.
To make it more obvious:
input = [1, 2, 3, 4, 5, 6]
output = [1, 4, 2, 5, 3, 6]
Define a function combine_inplace
that combines the ith element of the left half with the ith element of the right half of l
:
def combine_inplace(l):
mid = len(l) // 2
ptr = 0
for left, right in zip(l[:mid], l[mid:]):
l[ptr], l[ptr 1] = left, right
# Increment pointer ptr by 2 for the next combination
ptr = 2
combine_inplace
mutates the passed listl
- left half and right half are created using slice operator
- use
zip
to iterate over both list - increment
ptr
by 2 to get to the next list indices forl
If you don't want to mutate the list itself you can instead create a new list combined
that is returned by the function combine
:
def combine(l):
mid = len(l) // 2
combined = []
for left, right in zip(l[:mid], l[mid:]):
combined.extend((left, right))
return combined
- Does not mutate the passed list
l
- Initialise empty list
combined
to store the combined values - use
zip
to iterate over both list halves - Returns the list
combined
This uses the same logic as combine_inplace
but you keep the original list intact.
Both functions combine the elements of the left half with the right half of a given list. The only difference is that with combine
you have to store the returned list in a variable to access it.
>> l = [1, 1, 1, 2, 2, 2]
>> combine_inplace(l)
>> print(l)
[1, 2, 1, 2, 1, 2]
>> input_list = [1, 2, 3, 4, 5, 6]
>> output_list = combine(input_list)
>> print(output_list)
[1, 4, 2, 5, 3, 6]
Now using either combine
or combine_inplace
to combine elements of lists with a length > 2
inside a list:
ll = [[1, 2], [1, 2], [1, 1, 2, 2], [1, 2], [1, 2, 3, 4, 5, 6]]
# Non-destructive way using combine to create a new list comb_ll
comb_ll = []
for el in ll:
if len(el) > 2:
el = combine(el)
comb_ll.append(el)
# Mutates the original list
for i in range(len(ll)):
if len(ll[i]) > 2:
combine_inplace(ll[i])
In both cases you'll get the same result:
>> print(comb_ll)
[[1, 2], [1, 2], [1, 2, 1, 2], [1, 2], [1, 4, 2, 5, 3, 6]]
>> print(ll)
[[1, 2], [1, 2], [1, 2, 1, 2], [1, 2], [1, 4, 2, 5, 3, 6]]