Get key from a value(list) in a dic - python

Is there a way to retrive a key from values if the values is a list:
def add(self, name, number):
if name in self.bok.values():
print 'The name alredy exists in the telefonbok.'
else:
self.bok.update({number: []})
self.bok[number].append(name)
print self.bok
This works if i only have one element in the list:
self.bok.keys()[self.bok.values().index(my value i want to get the corresponding key)]
But if i insert more elements is gives me the error that it isnt in the list,
if u are wondering im creating an telephone book using class and dictionary so im supposed
to give and alias to the number and also be able to change the number on one name and alias should also get the new number. Would appriciate any help sorry if i'm blurry

If you find yourself wondering "how do I look up a key by its value?" it usually means that your dictionary is going the wrong way, or at least that you should be keeping two dictionaries. This is especially true if you notice yourself ensuring that the values are unique by hand!
At the moment, your conditional is never true (unless self.bok.values() is updated some other way), because name is (presumably) a string whereas self.bok.values() looks like it's a list of lists. If names should only appear once in the telephone book, that's a good hint that you should have a dictionary going the opposite direction.
Assuming you also need the number-to-name lookup, what I would do is add another dictionary to your class, and update them both whenever you add a new name/number pair.
import collections # defaultdict is a very nice object
# elsewhere, presumably in the __init__ method
self.name_to_number = {}
self.number_to_names = collections.defaultdict(list)
def add(self, name, number):
if name in self.name_to_number:
print 'The name alredy exists in the telefonbok.'
else:
self.name_to_number[name] = number
self.number_to_names[number].append(name)
If you're dead set on doing it the hard way for whatever reason, the findByValue method in Óscar López's answer is what you need.

Related

How to get result from a dictionary with lists as the values

I have a JSON file with n number of dictionaries as listed below in the snippet. I am trying to fetch the value against the key but it fails in my code when the value is defined as a list like in the below example for key affected_packages. I tried to check why my code fails, so it looks like it pulls no data out of it this fails. I just see two brackets [] as output instead of "thunderbird-0:78.9.1-1.el8_1","thunderbird-0:78.9.1-1.el8_2","thunderbird-0:78.9.1-1.el8_3","thunderbird-0:78.9.1-1.el7_9"
{"bugzilla_description":"CVE-2021-23992 Mozilla: A crafted OpenPGP key with an invalid user ID could be used to confuse the user","cvss_score":null,"cvss_scoring_vector":null,"CWE":"CWE-347","affected_packages":["thunderbird-0:78.9.1-1.el8_1","thunderbird-0:78.9.1-1.el8_2","thunderbird-0:78.9.1-1.el8_3","thunderbird-0:78.9.1-1.el7_9"],"resource_url":"https://access.redhat.com/hydra/rest/securitydata/cve/CVE-2021-23992.json","cvss3_scoring_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L","cvss3_score":"4.3"}
I am doing like below in my code as I need to prepare a worksheet. Sample snippet:
for i in range(offs):
ws.cell(row=r+1+i,column=2).value = v['current'][i]
if 'affected_packages' in list(tmp1.keys()):
ws.cell(row=r+1+index1,column=11).value = tmp1['affected_packages']
print("affected_packages done")
if 'advisories' in list(tmp1.keys()):
ws.cell(row=r+1+index2,column=13).value = tmp1['advisories']
print("advisories done")
Is there a way I can pull the value correctly for those defined as a list in the dictionary? I need a way so that it won't hamper my existing logic to pull value for normal key: value since while looking up into my JSON file.
So need something which can fulfil both whether my value in the dictionary is as a list or not as a list and I can get value against the keys in my json file.
As mentioned in the other answers, you can test the type of a variable using
if type(some_variable) == list:
# do what you need to do
You do mention that your code breaks, and I guess it's because inserting into a cell expects a String, not the list you pass in the line
ws.cell(row=r+1+index1,column=11).value = tmp1['affected_packages']
So how do we get a string out of a list of strings? It's pretty easy using the join method.
my_list = ["thunderbird-0:78.9.1-1.el8_1","thunderbird-0:78.9.1-1.el8_2","thunderbird-0:78.9.1-1.el8_3","thunderbird-0:78.9.1-1.el7_9"]
as_one_string = ", ".join(my_list)
print(as_one_string)
# Prints out 'thunderbird-0:78.9.1-1.el8_1, thunderbird-0:78.9.1-1.el8_2, thunderbird-0:78.9.1-1.el8_3, thunderbird-0:78.9.1-1.el7_9'
So combining the two ideas:
if 'affected_packages' in list(tmp1.keys()):
ws.cell(row=r+1+index1,column=11).value = tmp1['affected_packages'] if type(tmp1['affected_packages']) != list else ", ".join(tmp1['affected_packages'])
print("affected_packages done")
Quick feedback because I can't comment yet: Please always include an error message and/or the output you get when running your code when you ask a question
If I understand it correctly, you just need to determine if a value in dict is list. You can do that as below:
for i in d.items(): # gets key, value as a tuple.
if isinstance(i[1],list):
print('its a list, process it accordingly')
else:
print('Not a list')
Regarding your second problem, when you don't know if it is a list or something else, you can just check the type, maybe like this:
if type(tmp1['affected_packages']) == list:
# process the list
else:
# process other types
Since you don't know the data type, having this explicit type check seems necessary.

Assign a Range of Numbers to a Single Key with Dictionaries

I was working on a dictionary, but I came up with an issue. And the issue is, I want to be able to use more than 1 number in order to reference a key in a dictionary.
For example, I want the range of numbers between 1 and 5 to be all assigned to, let's say, "apple". So I came up with this:
my_dict['apple'] = range(1,5)
At the program's current state, its far from being able to run, so testing is an issue, but I do not receive any issues from my editor. I was just wondering, is this the correct way to go about this? Or is there a better way?
Thanks.
EDIT:
A little more info: I want to make a random integer with the randint function. Then, after Python has generated that number, I want to use it to call for the key assigned to the value of the random integer. Thing is, I want to make some things more common than others, so I want to make the range of numbers I can call it with larger so the chance of the key coming up becomes likelier. Sorry if it doesn't make much sense, but at the current state, I really don't even have code to show what I'm trying to accomplish.
You have the dictionary backwards. If you want to be able to recall, e.g., 'apple' with any of the numbers 1-5, you'd need the numbers to be the keys, not the values.
for i in range(1,6): # range(a,b) gives [a,b)
my_dict[i] = 'apple'
etc. Then, my_dict[4] == 'apple' and the same is true for the other values in the range.
This can create very large dictionaries with many copies of the same value.
Alternately, you can use range objects as dictionary keys, but the testing will be a bit more cumbersome unless you create your own class.
my_dict[range(1,6)] = 'apple'
n = random.randint(1, 5)
for key in my_dict:
if n in key:
print(my_dict[key])
...prints apple.
The value in a dictionary can be any arbitrary object. Whether it makes sense to use a given type or structure as a value only makes sense in the context of the complete script, so it is impossible to tell you whether it is the correct solution with the given information.

writing to a file using one of the key as index and other key as value

I am very new to programming as well as to python.
I have been trying to implement it, but without success and would like ur help.
I have a dictionary with weird key values. I need to use one of the key as my index number and other i.e second key as the value along with the value stored in the dictionary as the third column.
For e.g if the dictionary is
{'Michael', 'Student<matriculation no>', 'marks obtained' : 40 }
the result should be like this
Name Admission no marks obtained
Michael matriculation no 40
sara matriculation no 60
where matriculation no is the value extracted from the second key of the dictionary(different for each value)
and this goes on for about 100 rows.
kindly suggest a method to do this.
You don't have multiple keys. In your example, your key is the tuple ('Michael', 'Student', 'marks obtained') (your dictionary syntax is wrong, by the way: it should be {('Michael', 'Student', 'marks obtained') : 40} based on what you're implying).
If you are guaranteed that no two students will have the same name (perhaps you might include last name and middle initial!) then you may use just their names as keys. Then, it would make sense to have the value be a tuple (matriculation, marks obtained). Like so: {"Michael" : ('Student', 40)}.
When you want to print these students, you may say print name, students[name][0], "no", students[name][1], where students is your dictionary and name is a string which is the student's name e.g. 'Michael'.
I'm not sure what else you can have for matriculation besides 'Student' by the way. It seems to me that you don't need to include that, unless you can in fact have other values for that.
A good metaphor here is to think of 'Michael' as having some data associated with him, i.e. his matriculation status and the number of marks received. The state of being matriculated does not have 'Michael' associated with it (particularly) nor does having received 40 marks have 'Michael' associated with it (particularly), because these things can happen to other people. So, the proper key is the student's name. Keys are supposed to be unique - when they are not, you run into a problem known as collision, in which two or more data (values) are associated with the same thing (key).
Big edit:
After looking at your edited post it seems that your key should actually be the matriculation number, since it is never the same. So now your dictionary should be {matriculation_no : (name, marks)}. And printing is now print students[matriculation_no][0], "Admission", matriculation_no, students[matriculation_no][1] or something like that. It depends on whether you wanted "Admission" in your string.
Minor edit:
If you want to write to a file, use file.write() instead.

Python: My dictionary that stores first names won't store more than one first name at a time

So, I've created a Dictionary that stores first-names as a list within that dictionary. New names are added within the dictionary's list via a function. Now, this is where i have hit a snag:
Main Obstacle: The function overwrites new names that I add. If I add the name "George" to the list via the function, it will store the name "George". But, I want to add the name "Alfred" within the dictionary, it overwrites the name "George" and adds the name "Alfred".
I am sure you can see how problematic this is for someone who wants to add multiple names to the dictionary's list. The odd thing is that when I type out the exact same code into the interpreter and I individually append names to the dictionary's list, it works fine.
Here is the code:
def add(data,value):
data['names'] = {}
data['names']['first'] = []
data['names']['first'].append(value)
Didn't you ask this question already? (My previous answer)
You are always setting the data['names'] to an empty dictionary before appending value to it.
def add(data, value):
data.setdefault('names', {}).setdefault('first', []).append(value)
See python docs on dict.setdefault

How to rewrite this Dictionary For Loop in Python?

I have a Dictionary of Classes where the classes hold attributes that are lists of strings.
I made this function to find out the max number of items are in one of those lists for a particular person.
def find_max_var_amt(some_person) #pass in a patient id number, get back their max number of variables for a type of variable
max_vars=0
for key, value in patients[some_person].__dict__.items():
challenger=len(value)
if max_vars < challenger:
max_vars= challenger
return max_vars
What I want to do is rewrite it so that I do not have to use the .iteritems() function. This find_max_var_amt function works fine as is, but I am converting my code from using a dictionary to be a database using the dbm module, so typical dictionary functions will no longer work for me even though the syntax for assigning and accessing the key:value pairs will be the same. Thanks for your help!
Since dbm doesn't let you iterate over the values directly, you can iterate over the keys. To do so, you could modify your for loop to look like
for key in patients[some_person].__dict__:
value = patients[some_person].__dict__[key]
# then continue as before
I think a bigger issue, though, will be the fact that dbm only stores strings. So you won't be able to store the list directly in the database; you'll have to store a string representation of it. And that means that when you try to compute the length of the list, it won't be as simple as len(value); you'll have to develop some code to figure out the length of the list based on whatever string representation you use. It could just be as simple as len(the_string.split(',')), just be aware that you have to do it.
By the way, your existing function could be rewritten using a generator, like so:
def find_max_var_amt(some_person):
return max(len(value) for value in patients[some_person].__dict__.itervalues())
and if you did it that way, the change to iterating over keys would look like
def find_max_var_amt(some_person):
dct = patients[some_person].__dict__
return max(len(dct[key]) for key in dct)

Categories

Resources