yodish
yodish

Reputation: 763

iterate through multiple lists of strings to find a common value

I'm trying to come up with something to find the substring 'angle' in each of these lists of strings:

ListA = ['angle 45', 'color red', 'inside t']

ListB = ['angle 135', 'color blue', 'inside f']

ListC = ['above r', 'angle 315', 'color pink', 'inside o']

I need to add a couple checks

1) only if 'angle' exists in all 3 lists

2) And if listA's 'angle' value does not equal listC's angle value,

Then get listC's angle value, subtract 90 and put the new string back in the list. So, listC would now look like:

ListC = ['above r', 'angle 225', 'color red', 'inside r']

I've tried splitting these lists on white space to create lists like:

['angle', '45', 'color', 'red', 'inside', 't']

However, i'm having difficulty iterating through all 3 lists, then doing the subsequent checks, pulling a value and replacing. I'm wondering if I need to create a new dictionary or list to be able to fully implement this.

Update This is what I have that checks for 'angle ' in all three lists then splits up each list further. What I haven't figured out is now that i've split angle from it's value, i'm not sure how I check that listA's angle value does not equal listB's. I haven't gotten to pulling the value, updating it and putting it back.

if any("angle " in s for s in listA) and any("angle " in s for s in listB) \
    and any("angle" in s for s in listC):
    listASplit = []
    for word in listA:
        word = word.split(" ")
        listASplit.extend(word)

    listBSplit = []
    for word in listB:
        word = word.split(" ")
        listBSplit.extend(word)

    listCSplit = []
    for word in listC:
        word = word.split(" ")
        listCSplit.extend(word)

Upvotes: 0

Views: 516

Answers (5)

TemporalWolf
TemporalWolf

Reputation: 7952

Compartmentalize your work via functions:

def index_of_angle(lst):
    for string in lst:
        if string.startswith("angle"):
            return lst.index(string)
    # implicitly returns None if angle is not found

def get_angles(*lsts):
    return [index_of_angle(lst) for lst in lsts]

Now this is easy to follow:

a, b, c = get_angles(ListA, ListB, ListC)

if None not in [a, b, c]:  # Check 1 is obvious
    if ListA[a] != ListC[c]:  # Check 2 is obvious
        new_angle = int(ListC[c].split()[1]) - 90  # split by default is on spaces
        ListC[c] = "angle %d" % new_angle

To be even more explicit, you could rename get_angles to get_angles_or_none to make it clear it gives None if no angle is found.


To handle input where angle may appear more than once (and this input should be discarded):

def index_of_angle(lst):
    index_found = None
    for string in lst:
        if string.startswith("angle"):
            if index_found is not None:
                index_found = None  # if multiple angles found, set return to None
                break  # if two angles found, no need to keep looking
            index_found = lst.index(string)
    return index_found # returns angle or None if not found/multiple

This will be marginally slower, as we cannot return once we find angle (we must instead ensure that another angle entry does not exist first).

Upvotes: 1

vash_the_stampede
vash_the_stampede

Reputation: 4606

I'm sorry I was at the Browns game, could have made your life easier sooner :)

listd = [lista, listb, listc]

if 'angle' in ''.join(lista) and ''.join(listb) and ''.join(listc):
    for idx, item, in enumerate(lista):
        for x, i in enumerate(listc):
            if 'angle' in item and 'angle' in i:
                if item.split()[1] != i.split()[1]:
                    listc[x] = i.split()[0] + ' ' + str(int(i.split()[1]) - 90)

print(listd)
[['angle 45', 'color red', 'inside t'], ['angle 135', 'color blue',
'inside f'], ['above r', 'angle 225', 'color pink', 'inside o']]

Upvotes: 1

LetzerWille
LetzerWille

Reputation: 5658

def f(l):
    cnt  = 0
    for el in l:
        cnt+= len([x for x in el if 'angle' in x])
    if cnt == 3:
        if l[0][0] != l[1][0]:
            angle = l[2][1]
            n, d = angle.split()
            d = str(int(d) - 90)
            angle = n + " " + d
    l[2][1] = angle
    return l[2]

f([ListA, ListB, ListC])  

['above r', 'angle 225', 'color pink', 'inside o']

Upvotes: 1

Swift
Swift

Reputation: 1711

lista = ['angle 45', 'color red', 'inside t'] 
listb = ['angle 135', 'color blue', 'inside f'] 
listc = ['above r', 'angle 315', 'color pink', 'inside o']
kw = 'angle'
results = []

for item in lista:
    if kw in item:
        results.append(item)
for item in listb:
    if kw in item:
        results.append(item)
for x in range(len(listc)):
    if kw in item[x]:
        results.append(item)
        index = x

if int(results[0].split()[1]) != int(results[2].split()[1]):
    lastindex = results[2].split()
    listc[index] = lastindex[0]+' '+str(int(lastindex[1])-90)
for x in results:
    print(x)

So explained:

I added a new variable called kw and this just hold the keyword we are searching for.

I also created an empty list called results to store the matches and their values.

When we iterate listc we iterate the range of the length of the list so that we can extract an index (to replace the string later).

So, we check all of the lists for the keyword and append() the match to results

After that, we check that the first and last values DO NOT match. If this is true, then we can split the string we extracted from listc and then minus 90 from the value before joining it back together and replacing the string in listc

Upvotes: 2

krflol
krflol

Reputation: 1155

You've got a lot going on here, but I would agree that a dictionary would be better here.

To start with, let's parse the list

dictA = {}

for item in ListA:
    row = item.split(" ")
    dictA[row[0]] = row[1] 

Do the same with each list, then you can compare values of the dictionaries without looping further.

if dictA['angle'] != to dictC['angle']:
    ...dostuff...

Don't forget to cast to the appropriate type when nessesary

Upvotes: 3

Related Questions