Replacing items in a list with values from a dictionary - list

I have a dictionary. I want to replace an item of a list with corresponding dictionary value if a key in the dictionary is in the item. For example, if key 'C' is in any item like 'CCC', it will replace the 'CCC' with corresponding dictionary value. Here is my code.
l=['0', 'CCC', '0', 'C', 'D', '0']
dic={"A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "F": 6, "G": 7, "U": 8}
for i in l:
for k, v in dic.items():
if k in i: i=str(v)
print(l)
What I want to get is: l = ['0', '3', '0', '3', '4', '0']
but the list does not change at all. What am I doing wrong here?

The dictionary isn't changing because when you are iterating the list with for i in l: a new object i is created taking values from the list. Then you are changing the value of i with the appropriate value from the dictionary. However, you are only changing the value of object i. If you want to change the values from the list you should modify the list directly. You can change if k in i: i=str(v) to if k in i: l.insert(l.index(i), v). This will find the location (index) of the key in the list first and then insert the associated value in that index.
Full code:
l=['0', 'CCC', '0', 'C', 'D', '0']
dic={"A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "F": 6, "G": 7, "U": 8}
for i in l:
for k, v in dic.items():
if k in i: l.insert(l.index(k), v)
print(l)

Based on your comments you can use this example to replace the values in list l:
l = ["0", "CCC", "0", "C", "D", "0"]
dic = {"A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "F": 6, "G": 7, "U": 8}
out = [str(dic.get(list(set(v))[0], v)) for v in l]
print(out)
Prints:
['0', '3', '0', '3', '4', '0']

Related

How to match elements from arrays and only print matches?

I have two lists, i am trying to match one item from the first list to another from the second list under a certain condition (for example if they share the same number in the same location). i wrote my code to match the first set ['A','B','C',4,'D'] and only print the set from list2 that has 4 in the same location. so basically my output would be:
['A','B','C',4,'D']
[1, 2, 3, 4, 5]
well i can't figure out how to print only the match
here is my code:
list1 = [['A','B','C',4,'D'],['A','B','C',9,'D'],['A','B','C',5,'D'],['A','B','C',6,'D'],['A','B','C',7,'D']]
list2 = [[1,2,3,2,5],[1,2,3,5,5],[1,2,3,3,5],[1,2,3,4,5],[1,2,3,1,5],[1,2,3,2,5]]
for var in list1:
print var
for i in range(0,len(list2)):
for var1 in list2:
if list1[0][3] == list2[i][3]:
print var1
Your program would become easier, if you used izip of itertools. Assuming you just need to print the elements
from itertools import izip
list1 = [['A','B','C',4,'D'],['A','B','C',9,'D'],['A','B','C',5,'D'],['A','B','C',6,'D'],['A','B','C',7,'D']]
list2 = [[1,2,3,2,5],[1,2,3,5,5],[1,2,3,3,5],[1,2,3,4,5],[1,2,3,1,5],[1,2,3,2,5]]
for item1 in list1:
for item2 in list2:
for i,j in izip(item1, item2):
if i==j:
print i
By using izip two times, it would be much easier
from itertools import izip
list1 = [['A','B','C',4,'D'],['A','B','C',9,'D'],['A','B','C',5,'D'],['A','B','C',6,'D'],['A','B','C',7,'D']]
list2 = [[1,2,3,2,5],[1,2,3,5,5],[1,2,3,3,5],[1,2,3,4,5],[1,2,3,1,5],[1,2,3,2,5]]
for i in izip(list1,list2):
for item1, item2 in izip(i[0],i[1]):
if item1 == item2:
print item1
Almost. I am not sure if that is what you wanted but the following code prints all pairs which have the same number in the 4th location of the array:
list1 = [['A','B','C',4,'D'],['A','B','C',9,'D'],['A','B','C',5,'D'],
['A','B','C',6,'D'],['A','B','C',7,'D']]
list2 = [[1,2,3,2,5],[1,2,3,5,5],[1,2,3,3,5],[1,2,3,4,5],[1,2,3,1,5],
[1,2,3,2,5]]
for t in list1:
print t
for b in list2:
if t[3] == b[3]:
print b
Output is:
['A', 'B', 'C', 4, 'D']
[1, 2, 3, 4, 5]
['A', 'B', 'C', 9, 'D']
['A', 'B', 'C', 5, 'D']
[1, 2, 3, 5, 5]
['A', 'B', 'C', 6, 'D']
['A', 'B', 'C', 7, 'D']
Is that what you were looking for?

Why does my code filter out all the strings?

My code skips over some of the strings it seems.
def filter_list(l):
for i in l:
if type(i) == str:
l.remove(i)
return l
print filter_list([1, 2, 3, '4', '5', 6, '7', 8])
It outputs:
[1, 2, 3, '5', 6, 8]
skipping over the '5' string
as mentioned in the comment: you should not change a list while you are iterating over it (unless you really know what you are doing).
and isinstance is usually safer to use than a type comparison.
with a list-comprehension you could do this:
def filter_list(l):
return [item for item in l if not isinstance(item, str)]
print(filter_list([1, 2, 3, '4', '5', 6, '7', 8])) # [1, 2, 3, 6, 8]
When execution flow encounters the first string "4" at position 3, removes it and shifts all remaining items to the left so "5" will be at index 3. But the next loop iteration comes to position 4, so it skips "5".
Consider the following approach using filter() function to perform a proper filtering process:
def filter_list(l):
return list(filter(lambda i: not isinstance(i,str), l))
print filter_list([1, 2, 3, '4', '5', 6, '7', 8])
The output:
[1, 2, 3, 6, 8]
Removing elements, while iterating, is slow and dangerous. The best choice is to create a new list new_list = [x for x in l if not isinstance(x,str)] . If list is really big, you can firstly find all elements that match the condition and after remove them
strings = [i for i,x in enumerate(l) if isinstance(x,str)]
for x in reversed(strings):
del l[x]
So the first choice (the fastest):
def filter_list(l):
return [x for x in l if not isinstance(x, str)]
print(filter_list([1, 2, 3, '4', '5', 6, '7', 8]))
The second (if number of values to delete is small, but size of list is big):
def filter_list(l):
strings = [i for i, x in enumerate(l) if isinstance(x, str)]
for x in reversed(strings):
del l[x]
l = [1, 2, 3, '4', '5', 6, '7', 8]
filter_list(l)
print(l)

Finding the value of each letter in a word using map and reduce

I have a function wordScore(word, scoreList). The word is a string that consists of only letters and scoreList is a list containing the value of each letter in the alphabet:
scoreList = [ ["a", 1], ["b", 3], ["c", 3], ["d", 2], ["e", 1],
["f", 4], ["g", 2], ["h", 4], ["i", 1], ["j", 8],
["k", 5], ["l", 1], ["m", 3], ["n", 1], ["o", 1], ["p", 3],
["q", 10], ["r", 1], ["s", 1], ["t", 1], ["u", 1], ["v", 4],
["w", 4], ["x", 8], ["y", 4], ["z", 10] ]
I have to find the total score of a word and then return it using map and reduce. Example:
wordScore('agile', scoreList)
>>> 6
I believe that I am not able to do this problem because I am not sure what map does. I would really appreciate some help.
Second Problem:
So now I am given a list of letters that(lets say listOfwords = ["a", "am", "at", "apple", "bat", "bar", "babble", "can", "foo", "spam", "spammy", "zzyzva"]) When I input a list of letters in scoreList(Rack) (such as scoreList(["a", "s", "m", "t", "p"]) then it should output all possible words that can be made with the letters that are in listOfwords. So basically it would be like:
>>> scoreList(["a", "s", "m", "t", "p"])
[['a', 1], ['am', 4], ['at', 2], ['spam', 8]]
>>> scoreList(["a", "s", "m", "o", "f", "o"])
[['a', 1], ['am', 4], ['foo', 6]]
This is my code so far:
def scoreList(Rack):
test = [x for x in Dictionary if all(y in Rack for y in x)]
return test
However when I run this it only gives me the words that can be made with the letters and I'm not sure how to get the score for each word. Could I possibly use wordScore? Also same restriction apply.
Map creates a sequence by applying a function to every items in a sequence:
>>> map(lambda x: x + 1, [1, 2, 3])
[2, 3, 4]
So to solve your problem:
If you can use dict, loop over all letters in word and map it to its score. Then sum all letter scores with reduce:
def wordScore(word, score_list):
score_dict = dict(score_list)
letter_scores = map(lambda letter: score_dict[letter], word)
return reduce(lambda x, y: x + y, letter_scores)
If you cannot, loop over all letters in score list and multiply each score by number of occurence of letter in word, then sum all letter scores with reduce:
def wordScore(word, score_list):
letter_scores = map(
lambda letter_score: word.count(letter_score[0]) * letter_score[1],
score_list
)
return reduce(lambda x, y: x + y, letter_scores)
Read map documentation in python 2.7

Return indices of all matching nested sub-lists within a list

Given a list with many possible sub-lists which are nested to an arbitrary depth and have a variable number of elements, is there a way to return the indices of all the instances of all sub-lists which meet certain criteria?
For example:
list1 = [1, 4, 7, ["a", "h", "b"], 2]
list2 = [1, 4, 7, "x", "g", ["a", 5, 8, "p", "b"], 2, 4, 7, "k", 9]
list3 = [1, 4, 7, ["a", "z", ["a", 6, "b"], "b"], 5, 3]
list4 = [1, 4, 7, ["a", "b", "c"], 3, 4]
sublist_function(list1, {[0]:'a', [-1]: 'b'})
# should return [[3]] (One instance of a matching sub-list (whose 0th element is 'a' and whose last element is 'b') found at list1[3])
sublist_function(list2, {[0]:'a', [-1]: 'b'})
# should return [[5]] (One instance of a matching sub-list, found at list2[5])
sublist_function(list3, {[0]:'a', [-1]: 'b'})
# should return [[3], [3][2]] (Two instances of a matching sub-list, found at list3[3] and list3[3][2])
sublist_function(list4, {[0]:'a', [-1]: 'b'})
# should return [] (There are no instances of a matching sub-list in list4)
I thought it would be a simple matter to adjust a function's code that tests for the presence/absence of the sub-list into one that would return the indices of the sub-lists, but this is proving to be quite a challenge for a beginning programmer like myself. The original function's code can be found in an answer to a previous question of mine from #AdamSmith, Find generic sub-lists within a list
UPDATE: Using How to find the number of nested lists in a list? as a guide, the following is the best I have been able to come up with so far, though 1) it only returns the LAST index of each matching sub-list and 2) replaces the last index of a matching sub-list with the last index of the first-occurring identical sub-list. I'm not even concerned that it doesn't have an argument to specify which characteristics of a list to match, but instead defines it within the function itself - that's icing on the cake at this point:
def sublist_function(lst, ind=None):
if ind is None:
ind = []
for el in lst:
if isinstance(el, list) and el[0] == 'a' and el[-1] == 'b':
ind.append([lst.index(el)])
sublist_function(el, ind)
elif isinstance(el, list):
sublist_function(el, ind)
return ind
list3 = [1, 4, 7, ["a", "z", ["a", 6, "b"], "b"], 5, 3]
print(sublist_function(list3)) #should return '[[3], [3][2]]'
>> [[3], [2]]
list5 = [1, 4, ["a", 5, "b"], 3, 4, 6, ["a", 5, "b"], 5]
print(sublist_function(list5)) #identical sub-lists (should return [[2], [6]])
>> [[2], [2]]
list6 = [1, 4, ["a", 7, "b"], 3, 4, 6, ["a", 5, "b"], 5]
print(sublist_function(list6)) #unique sub-lists (correctly returns [[2], [6]])
>> [[2], [6]]

Nested list remove duplicate list

In a nested list (like the one below) that is continuous,
I want to remove duplicate entry where first and third are equal values. What is the most efficient way of doing this?
[[a, 1, a], [b, 1, b], [c, 2, d],[e, 4,g]
Return
[[c, 2, d],[e, 4,g]]
>>> seq = [['a', 1, 'a'], ['b', 1, 'b'], ['c', 2, 'd'],['e', 4, 'g']]
>>> seq = [item for item in seq if item[0] != item[2]]
>>> print seq
[['c', 2, 'd'], ['e', 4, 'g']]
What you want to do is go through each sublist, and go through each item in that sublist. I there is a duplicate item in that sublist set the flag to True and ignore it, if not then append that list to a new list.
lists = [['a', 1, 'a'], ['b', 1, 'b'], ['c', 2, 'd'],['e', 4,'g']]
newLists = []
for l in lists:
if l[0] != l[len(l) - 1]:
newLists.append(l)
print newLists