Loop through dictionary keys to get values based on input - python

1) In my program I start with prompting a user for input.
2) I would then like to loop through the users input to get all the characters in that string, query each character individually against the dictionaries keys.
3) If a character from the input matches a key in the dictionary, I want that key's value returned.
4) This needs to be repeated for each character and the result should print those values returned in a string
To try and explain further, here is my dictionary:
dataDict = {
"a":"1",
"b":"2",
"c":"3",
}
For example:
If my input is abc, my result should be 123
If my input is cba, my result should be 321
and so on...
So far, this works if the string is only one character using the below code.
If i enter two characters, it just returns nothing.
dataInput=input("Enter stuff: ")
for key,value in dataDict.items():
if dataInput == key:
print(value)
How can I acheive the results i'm after?

You shouldn't be looping over the dict to find the matching keys, that's very inefficient. A dict is designed to do fast lookups: you give it the key and it gives you the value. Eg, dataDict["a"] results in "1".
Also, as Tim Pietzcker mentions, doing if dataInput == key will only work if dataInput consists of a single letter, because it compares the whole dataInput string to key.
Here's a simple way to do the desired conversion. We do the lookups in a list comprehension, which creates a list of the converted values, and then we pass that list to .join to create a string. (I've changed the names of your variables to conform with the PEP-008 style guide).
data_dict = {
"a": "1",
"b": "2",
"c": "3",
}
data_input = "aabbccba"
s = ''.join([data_dict[c] for c in data_input])
print(s)
output
11223321
However, that's not safe: it will fail with KeyError if data_input contains a char that's not in the dictionary. Here's a better way: it adds an empty string if it gets a bad char.
data_input = "aaxbbcycbaz"
s = ''.join([data_dict.get(c, '') for c in data_input])
print(s)
output
11223321
Alternatively, we could convert bad data to some special value, eg 0.
data_input = "aaxbbcycbaz"
s = ''.join([data_dict.get(c, '0') for c in data_input])
print(s)
output
11022303210
Just for fun, here's a "functional" version. Guido would probably not approve of this one. :)
data_input = "aaxbbcycbaz"
print(''.join(filter(None, map(data_dict.get, data_input))))
11223321

You should be iterating over the input string, not the dictionary. Also, you might want to use .get() in case the users enters a characters that's not in the dictionary:
for letter in dataInput:
print(dataDict.get(letter,"X"))
This will print each letter on its individual line. If you want to print them in a single line, you can add the end="" parameter to the print function (and print an empty line after you're done).
The comparison you're doing would never work (in the first iteration, it would amount to if "abc" == "a", I hope that makes it obvious).

You're iterating through the wrong thing. You should be iterating through the input. You don't need to iterate through the dict, because you can just look up by key.

Related

How to add a value to a dictionary that has a duplicate key

I have this problem where I would like to add a value to a dictionary but the key is duplicate.
I would like the key to to hold a list with multiple values
this is what I have tried
def storingPassword():
username=("bob")#key,
password=("PASSWROD1")#value
allpasswords={
"jeff":"jeff 123 ",
"bob" : "bob 123"
}
if username not in allpasswords:
allpasswords[username]=password
else:
allpasswords[username].append(password)
return allpasswords
but i keep getting this error
"AttributeError: 'str' object has no attribute 'append'"
I expect a output something like this;
"jeff":"jeff 123 ",
"bob" : ["bob 123","PASSWORD1"]
That's because the value in your allpasswords dict is a string and you are trying to treat it like a list. Why are you trying to make your data structure complex with few values as list and few as string? I recommend to convert everything to list for a simpler logic.
Hence your code should be like this:
allpasswords={
"jeff": ["jeff 123 "],
"bob" : ["bob 123"]
}
allpasswords[username].append(password)
Instead of using dict object, you can use collections.defaultdict. It will let you define a dict with default value as list. So you don't need to even explicitly initialise value of new key as list. For example:
from collections import defaultdict
my_dict = defaultdict(list)
my_dict['new_key'].append('new_value')
# dictionary will hold the value:
# {'new_key': ['new_value']})
Initiate your dictionary entry with a list instead of just a string.
allpasswords[username] = [password] # List containing a single password
You will then be able to append to it.
(Having some entries contain a string while others contain a list of strings is best avoided - when it is time to look them up or print them, you would have to check each time whether it is a list or string.)

Trouble converting "for key in dict" to == for exact matching

Good morning,
I am having trouble pulling the correct value from my dictionary because there are similar keys. I believe I need to use the == instead of in however when I try to change if key in c_item_number_one: to if key == c_item_number_one: it just returns my if not_found: print("Specify Size One") however I know 12" is in the dictionary.
c_item_number_one = ('12", Pipe,, SA-106 GR. B,, SCH 40, WALL smls'.upper())
print(c_item_number_one)
My formula is as follows:
def item_one_size_one():
not_found = True
for key in size_one_dict:
if key in c_item_number_one:
item_number_one_size = size_one_dict[key]
print(item_number_one_size)
not_found = False
break
if not_found:
print("Specify Size One")
item_one_size_one()
The current result is:
12", PIPE,, SA-106 GR. B,, SCH 40, WALL SMLS
Specify Size One
To split the user input into fields, use re.split
>>> userin
'12", PIPE,, SA-106 GR. B,, SCH 40, WALL SMLS'
>>> import re
>>> fields = re.split('[ ,]*',userin)
>>> fields
['12"', 'PIPE', 'SA-106', 'GR.', 'B', 'SCH', '40', 'WALL', 'SMLS']
Then compare the key to the first field, or to all fields:
if key == fields[0]:
There are two usages of the word in here - the first is in the context of a for loop, and the second entirely distinct one is in the context of a comparison.
In the construction of a for loop, the in keyword connects the variable that will be used to hold the values extracted from the loop to the object containing values to be looped over.
e.g.
for x in list:
Meanwhile, the entirely distinct usage of the in keyword can be used to tell python to perform a collection test where the left-hand side item is tested to see whether it exists in the rhs-object's collection.
e.g.
if key in c_item_number_one:
So the meaning of the in keyword is somewhat contextual.
If your code is giving unexpected results then you should be able to replace the if-statement to use an == test, while keeping everything else the same.
e.g.
if key == c_item_number_one:
However, since the contents of c_item_number_one is a tuple, you might only want to test equality for the first item in that tuple - the number 12 for example. You should do this by indexing the element in the tuple for which you want to do the comparison:
if key == c_item_number_one[0]:
Here the [0] is telling python to extract only the first element from the tuple to perform the == test.
[edit] Sorry, your c_item_number_one isn't a tuple, it's a long string. What you need is a way of clearly identifying each item to be looked up, using a unique code or value that the user can enter that will uniquely identify each thing. Doing a string-match like this is always going to throw up problems.
There's potential then for a bit of added nuance, the 1st key in your example tuple is a string of '12'. If the key in your == test is a numeric value of 12 (i.e. an integer) then the test 12 == '12' will return false and you won't extract the value you're after. That your existing in test succeeds currently suggests though that this isn't a problem here, but might be something to be aware of later.

update string from a dictionary with the values from matching keys

def endcode(msg,secret_d):
for ch in msg:
for key,value in secret_d:
if ch == key:
msg[ch] = value
return msg
encode('CAN YOU READ THIS',{'A':'4','E':'3','T':'7','I':'1','S':'5'})
This is my code. What I am trying to do here is for every characters in a string msg, the function should search in the dictionary and replace it with the mapping string if the character ch is a key in the dictionary secret_d.
If ch is not a key in secret_d than keep it unchanged.
For the example, the final result is should be 'C4N YOU R34D 7H15'
Your function name is endcode but you are calling encode.
But more important, I'll give you a hint to what's going on. This isn't going to totally work, but it's going to get you back on track.
def endcode(msg,secret_d):
newstr=""
for ch in msg:
for key,value in secret_d.iteritems():
if ch == key:
newstr=newstr+value
print(msg)
endcode('CAN YOU READ THIS',{'A':'4','E':'3','T':'7','I':'1','S':'5'})
But if you want a complete answer, here is mine.
A few issues:
As rb612 pointed out, there's a typo in your function definition ("endcode")
you are doing nothing with the return value of your function after calling it
msg[ch] is trying to assign items in a string, but that's not possible, strings are immutable. You'll have to build a new string. You cannot "update" it.
in order to iterate over (key, value) pairs of a dictionary d, you must iterate over d.items(). Iterating over d will iterate over the keys only.
That being said, here's my suggestion how to write this:
>>> def encode(msg, replacers):
... return ''.join([replacers.get(c, c) for c in msg])
...
>>> result = encode('CAN YOU READ THIS',{'A':'4','E':'3','T':'7','I':'1','S':'5'})
>>> result
'C4N YOU R34D 7H15'
Things to note:
dict.get can be called with a fallback value as the second argument. I'm telling it to just return the current character if it cannot be found within the dictionary.
I'm using a list comprehension as the argument for str.join instead of a generator expression for performance reasons, here's an excellent explanation.

Python string/float comparison

I've run into the following issue, with my code below. Basically I have a list of objects with an id and a corresponding weight, and I have another list of id's. I want to use only the weights of the objects matching the id's in the second list.
d_weights = [{'d_id':'foo', 'weight': -0.7427}, ...]
d_ids = ['foo', ...]
for dtc_id in d_ids:
d_weight = next((d['weight'] for d in d_weights if d['d_id'] == dtc_id), "")
print str(d_weight)
if str(d_weight) != "":
print "not empty string! "+str(d_weight)
The output for this is:
-0.7427
0.0789
-0.0039
-0.2436
-0.0417
not empty string! -0.0417
Why is only the last one not empty when I can print them fine and they are obviously not equal to an empty string? How do I check that the next() actually returned something before using it?
You haven't correct algorithm.
So d_weight = next((d['weight'] for d in d_weights if d['d_id'] == dtc_id), "") iterate only once.
On every cycle for weight_dict in d_weights: you've got only first dict of d_weights.
Without more data, i can't reproduce your output.
In my case it works fine:
-0.7427
not empty string! -0.7427
-0.327
not empty string! -0.327
Correct code you can find in DhiaTN's answer.
just iterate of the list of the keys and get the values from each dict :
for weight_dict in d_weights
for key in d_ids:
print weight_dict.get(key, "")

TypeError when using replace() from dictionary

First of all: Please keep in mind that I'm very much a beginner at programming.
I'm trying to write a simple program in Python that will replace the consonants in a string with consonant+"o"+consonant. For example "b" would be replaced with "bob" and "d" would be replaced with "dod" (so the word "python" would be changed to "popytothohonon").
To do this I created a dictionary, that contained the pairs b:bob,c:coc,d:dod etc. Then I used the replace() command to read through the word and replace the consonants with their translation in the dictionary. The full piece of code looks like this:
def replacer(text):
consonant='bcdfghjklmnpqrstvwxz'
lexicon={}
for x in range(0,len(consonant)):
lexicon[x]=(consonant[x]),(consonant[x]+'o'+consonant[x])
for i,j in lexicon.items():
text=(text.replace(i,j))
return text
Now, when I try to call this function I get the following error:
Traceback (most recent call last):
File "D:\x\x.py", line 37, in <module>
print(replacer("python"))
File "D:\x\x.py", line 17, in replacer
text=(text.replace(i,j))
TypeError: Can't convert 'int' object to str implicitly
But I'm not using any ints! There's got to be something wrong with the dictionary, because everything works when i make it "by hand" like this:
list={'b':'bob', 'c':'coc', 'd':'dod', 'f':'fof', 'g':'gog', 'h':'hoh'......}
But when I print the "non-hand-made" dictionary everything seems to be in order:
{0: ('b', 'bob'), 1: ('c', 'coc'), 2: ('d', 'dod'), 3: ('f', 'fof')........
What am I doing wrong?
lexicon is a dictionary with integers as keys and tuples as values. when you iterate over it's items, you're getting tuples of the form (integer,tuple). You're then passing that integer and tuple to text.replace as i and j which is why it's complaining. Perhaps you meant:
for i,j in lexicon.values():
...
For this simple replacement, str.replace is fine, but for more complicated replacements, the code will probably be more robust (and possibly execute faster!) if you use re.sub instead.
Also, as pointed out in the comments, for this case, a better data structure would be to use a list:
lexicon = [ (x,'{0}o{0}'.format(x)) for x in chars ]
Now you can build your dict from this list if you really want:
lexicon = dict(enumerate(lexicon))
but there's probably no need. And in this case, you'd iterate over lexicon directly:
for i,j in lexicon:
...
If you're only going to do this once, you could even do it lazily without ever materializing the list by using a generator expression:
lexicon = ( (x,'{0}o{0}'.format(x)) for x in chars )
I guess what you wanted to achieve is lexicon mapping consonant to replacement. It may be done this way:
lexicon = { c: c+'o'+c for c in consonant }
which is equivalent of:
for c in consonant:
lexicon[c] = c+'o'+c
No need for dictionaries this time, just iterate over characters of text, add vovels or consonant+o+consonant to an result array and join it to a string at the end:
def replacer(text):
consonants = set('bcdfghjklmnpqrstvwxz')
result = []
for c in text:
if c in consonants:
result.append(c+"o"+c)
else:
result.append(c)
return "".join(result)
print(replacer("python"))
For advanced users:
def replacer(text):
return re.sub(r"[bcdfghjklmnpqrstvwxz]", r"\g<0>o\g<0>", text)
And to answer "What am I doing wrong?" - dictionaries are useful for arbitrary keys, usually list.append() is preferred from using keys 0-n in a dict. And since you are not interested in a consonant's position, you can iterate over strings directly like this:
for x in consonant:
lexicon[x] = x+"o"+x
no ... your keys in the handmade version are strings ... your kets in the other version are ints ... ints have no replace method

Categories