简体   繁体   中英

Replace element in list with element from another list - Python

I have a list named rule.start. In this list, all elements are equal to an element from another list called com.empty . I want the element from rule.start to be replaced by the element that comes AFTER the same element from com.empty . How would I do this?

rule.start looks like this:

['F', 'L', 'G', 'L', 'F', 'R', 'F', 'R', 'F', 'L', 'G', 'L', 'F', 'L', 'F', 'L', 'G', 'L', 'F', 'L',........]

com.empty looks like this:

['F', ['fd'], 'G', ['fd'], 'L', ['lt', '60'], 'R', ['rt', '60']]

I have tried this:

wut = 0    
for elem in rule.start:
    v = 1
    for mel in com.empty[::2]:
        if elem == mel:
            rule.start[wut] = com.empty[v]
            print elem
            print mel
            wut +=1
            v += 2

But it just replaces all element of rule.start with ['fd']

In the end, I want to evaluate all elements as commands, that looks like this: fd(var, scale)

and this: rt(var, 60) # 60 is from the list.

First, this would be much easier to write, and a lot more efficient, if you had a dictionary, mapping keys to values, instead of a list of alternating keys and values. You can do that as a one-liner:

mapping = dict(zip(com.empty[::2], com.empty[1::2]))

But if you don't understand how that works, you can do this, which you should be able to understand (based on your code).

mapping = {}
key = None
for mel in com.empty:
    if key is None:
        key = mel
    else:
        mapping[key] = mel
        key = None

Or, even better, if possible, change your code to build a dict instead of a list of alternating values in the first place.


Now, once you have this, your loop becomes dead simple, and very hard to get wrong:

for wut, elem in enumerate(rule.start):
    rule.start[wut] = mapping.get(elem, elem)

I'm using enumerate so you don't have to keep track of wut manually, and I'm using the dict.get method instead of looping over all the keys and values, which is the tricky part that you got lost in.

Or, even more simply:

rule.start = [mapping.get(elem, elem) for elem in rule.start]

But, if you want to know what's wrong with your attempt:

You start off v = 1 . For each mel , you increment v by 2 if elem == mel . Otherwise, it stays at 1. So, the first time elem == mel , you're going to have v = 1 , so you're going to assign com.empty[1] to rule.start[wut] . If you move the v + 2 outside the loop, that will fix this problem.

You also have a similar problem with wut += 1 being in the wrong place. It should be updated for every elem ; instead, it's updated for every elem and mel that match, which could be 0 times or (theoretically) 3 times.

Getting this stuff right is a big source of errors, which is exactly why enumerate exists.

I would be tempted to start by rewriting com.empty as a dict, which is what you really want here.

c2 = {key:val for (key, val) in zip (com.empty[0::2], com.empty[1::2])}

Then it's pretty easy:

rule.start.new = [c2[key] for key in rule.start]

of course, this fails if you have a key in rule.start which is not in com.empty - I'll let you dot the i's and cross the t's to make it safe for your use

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM