One liner for poping list of lists based on condition
Question:
I’ve got the following lists:
leftoverbricks = [['purple1', 'y8', 'x0', 'y8', 'x1'], ['purple2', 'y6', 'y0', 'x8', 'y0'], ['purple3', 'z2', 'x8', 'z2', 'x0']]
and
startingbrick = ['purple3', 'z2', 1, 1]
I’d like to pop an element from leftoverbricks where startingbrick[0]
matches first element of list of list from leftoverbricks, so leftoverbricks[][0]
I’ve created a function that works:
def removebrick(tempbrick, templist):
reducedlist = templist
for tempelement in reducedlist:
if tempelement[0] == tempbrick[0]:
reducedlist.pop(reducedlist.index(tempelement))
return reducedlist
and which gives the correct result of:
reducedleftoverbricks = removebrick(startingbrick, leftoverbricks)
reducedleftoverbricks = [['purple1', 'y8', 'x0', 'y8', 'x1'], ['purple2', 'y6', 'y0', 'x8', 'y0']]
But it’s not elegant. I hope such thing can be done with one liner and by mutating original leftoverbricks
list rather than creating a new list variable reducedleftoverbricks
. I did a few attempts at one liner list comprehension but so far failed.
Answers:
Personally, I’d consider using a filter. Note that the filter is going to be lazily evaluated, so you can evaluate the whole filter in the spot where you’d like the reduced list.
for brick in filter(lambda n: n[0] != startingbrick[0], leftoverbricks):
do_more_work(brick)
This would be a good use-case for filter().
e.g.,
leftoverbricks = [['purple1', 'y8', 'x0', 'y8', 'x1'], ['purple2', 'y6', 'y0', 'x8', 'y0'], ['purple3', 'z2', 'x8', 'z2', 'x0']]
startingbrick = ['purple3', 'z2', 1, 1]
def removebrick(tempbrick, templist):
key, *_ = templist
return list(filter(lambda v: v[0] != key, tempbrick))
print(removebrick(leftoverbricks, startingbrick))
Output:
[['purple1', 'y8', 'x0', 'y8', 'x1'], ['purple2', 'y6', 'y0', 'x8', 'y0']]
Note:
This does not modify the input list (leftoverbricks). If you want it to be destructive then just assign the return value from this function to the appropriate variable
You can use a list comprehension to remove the elements from leftoverbricks
that match the first element of startingbrick
.
Example:
leftoverbricks = [['purple1', 'y8', 'x0', 'y8', 'x1'], ['purple2', 'y6', 'y0', 'x8', 'y0'], ['purple3', 'z2', 'x8', 'z2', 'x0']]
startingbrick = ['purple3', 'z2', 1, 1]
leftoverbricks = [brick for brick in leftoverbricks if brick[0] != startingbrick[0]]
print(leftoverbricks)
This will modify leftoverbricks
in place, so you don’t need to create a new list variable.
Otuput:
[['purple1', 'y8', 'x0', 'y8', 'x1'], ['purple2', 'y6', 'y0', 'x8', 'y0']]
I’ve got the following lists:
leftoverbricks = [['purple1', 'y8', 'x0', 'y8', 'x1'], ['purple2', 'y6', 'y0', 'x8', 'y0'], ['purple3', 'z2', 'x8', 'z2', 'x0']]
and
startingbrick = ['purple3', 'z2', 1, 1]
I’d like to pop an element from leftoverbricks where startingbrick[0]
matches first element of list of list from leftoverbricks, so leftoverbricks[][0]
I’ve created a function that works:
def removebrick(tempbrick, templist):
reducedlist = templist
for tempelement in reducedlist:
if tempelement[0] == tempbrick[0]:
reducedlist.pop(reducedlist.index(tempelement))
return reducedlist
and which gives the correct result of:
reducedleftoverbricks = removebrick(startingbrick, leftoverbricks)
reducedleftoverbricks = [['purple1', 'y8', 'x0', 'y8', 'x1'], ['purple2', 'y6', 'y0', 'x8', 'y0']]
But it’s not elegant. I hope such thing can be done with one liner and by mutating original leftoverbricks
list rather than creating a new list variable reducedleftoverbricks
. I did a few attempts at one liner list comprehension but so far failed.
Personally, I’d consider using a filter. Note that the filter is going to be lazily evaluated, so you can evaluate the whole filter in the spot where you’d like the reduced list.
for brick in filter(lambda n: n[0] != startingbrick[0], leftoverbricks):
do_more_work(brick)
This would be a good use-case for filter().
e.g.,
leftoverbricks = [['purple1', 'y8', 'x0', 'y8', 'x1'], ['purple2', 'y6', 'y0', 'x8', 'y0'], ['purple3', 'z2', 'x8', 'z2', 'x0']]
startingbrick = ['purple3', 'z2', 1, 1]
def removebrick(tempbrick, templist):
key, *_ = templist
return list(filter(lambda v: v[0] != key, tempbrick))
print(removebrick(leftoverbricks, startingbrick))
Output:
[['purple1', 'y8', 'x0', 'y8', 'x1'], ['purple2', 'y6', 'y0', 'x8', 'y0']]
Note:
This does not modify the input list (leftoverbricks). If you want it to be destructive then just assign the return value from this function to the appropriate variable
You can use a list comprehension to remove the elements from leftoverbricks
that match the first element of startingbrick
.
Example:
leftoverbricks = [['purple1', 'y8', 'x0', 'y8', 'x1'], ['purple2', 'y6', 'y0', 'x8', 'y0'], ['purple3', 'z2', 'x8', 'z2', 'x0']]
startingbrick = ['purple3', 'z2', 1, 1]
leftoverbricks = [brick for brick in leftoverbricks if brick[0] != startingbrick[0]]
print(leftoverbricks)
This will modify leftoverbricks
in place, so you don’t need to create a new list variable.
Otuput:
[['purple1', 'y8', 'x0', 'y8', 'x1'], ['purple2', 'y6', 'y0', 'x8', 'y0']]