How to use string value as a variable name in Python? [duplicate] - python

This question already has answers here:
How do I create variable variables?
(17 answers)
Closed 6 years ago.
Suppose I have lists as follows:
candy = ['a','b','c']
fruit = ['d','e','f']
snack = ['g','h','i']
and a string
name = 'fruit'
I want to use string name for accessing list and it's content. In this case it should be fruit. I will use name for iterating list. As:
for x in name:
print x

You can use globals() like so:
for e in globals()[name]:
print(e)
Output:
d
e
f
And if your variables happen to be in some local scope you can use locals()
OR you can create your dictionary and access that:
d = {'candy': candy, 'fruit': fruit, 'snack': snack}
name = 'fruit'
for e in d[name]:
print(e)

I don't understand what exactly you're trying to achieve by doing this but this can be done using eval. I don't recommend using eval though. It'd be better if you tell us what you're trying to achieve finally.
>>> candy = ['a','b','c']
>>> fruit = ['d','e','f']
>>> snack = ['g','h','i']
>>> name = 'fruit'
>>> eval(name)
['d', 'e', 'f']
EDIT
Look at the other answer by Sнаđошƒаӽ. It'll be better way to go. eval has security risk and I do not recommend its usage.

Use a dictionary!
my_dictionary = { #Use {} to enclose your dictionary! dictionaries are key,value pairs. so for this dict 'fruit' is a key and ['d', 'e', 'f'] are values associated with the key 'fruit'
'fruit' : ['d','e','f'], #indentation within a dict doesn't matter as long as each item is separated by a ,
'candy' : ['a','b','c'] ,
'snack' : ['g','h','i']
}
print my_dictionary['fruit'] # how to access a dictionary.
for key in my_dictionary:
print key #how to iterate through a dictionary, each iteration will give you the next key
print my_dictionary[key] #you can access the value of each key like this, it is however suggested to do the following!
for key, value in my_dictionary.iteritems():
print key, value #where key is the key and value is the value associated with key
print my_dictionary.keys() #list of keys for a dict
print my_dictionary.values() #list of values for a dict
dictionaries by default are not ordered, and this can cause problems down the line, however there are ways around this using multidimensional arrays or orderedDicts but we will save this for a later time!
I hope this helps!

Related

how do you append a list to a dictionary value in Python?

So if you have some dictionary like this
dictionary={}
dictionary['a']=1
dictionary['a']=2
print(dictionary)
this would print {'a':2} and replaces the 1
Is there any way I can add 2 to the key 'a' as a list ?
I know i can do something this like:
dictionary['a']=[1,2]
but I don't want to do it like this.
Essentially what i am asking is how can i add the new value to my key using a list instead of replacing the previous value.
Appreciate the help!
dictionary = {}
dictionary['a'] = []
dictionary['a'].append(1)
dictionary['a'].append(2)
print(dictionary)
It would be worth considering using a defaultdict if every value in the dict is/will be a list:
from collections import defaultdict
d = defaultdict(list)
d['a'].append(1)
d['a'].append(2)

Indexing Dict with Multiple values at one key

I'm new to python and I was wondering if there's a way for me to pull a value at a specific index. Let's say I have a key with multiple values(list) associated with it.
d = {'ANIMAL' : ['CAT','DOG','FISH','HEDGEHOG']}
Let's say I want to iterate through values and print out the value if it's equal to 'DOG'. Do Values, Key pairs have a specific index associated with the position of Values?
I've try reading up on dict and how it works apparently you can't really index it. I just wanted to know if there's a way to get around that.
You can perform the following (comments included):
d = {'ANIMAL' : ['CAT','DOG','FISH','HEDGEHOG']}
for keys, values in d.items(): #Will allow you to reference the key and value pair
for item in values: #Will iterate through the list containing the animals
if item == "DOG":
print(item)
print(values.index(item)) #will tell you the index of "DOG" in the list.
So maybe this will help:
d = {'ANIMAL' : ['CAT','DOG','FISH','HEDGEHOG']}
for item in d:
for animal in (d[item]):
if animal == "DOG":
print(animal)
Update -What if I want to compare the string to see if they're equal or not... let say if the value at the first index is equal to the value at the second index.
You can use this:
d = {'ANIMAL' : ['CAT','DOG','FISH','HEDGEHOG']}
for item in d:
for animal in (d[item]):
if animal == "DOG":
if list(d.keys())[0] == list(d.keys())[1]:
print("Equal")
else: print("Unequal")
Keys and values in a dictionary are indexed by key and do not have a fixed index like in lists.
However, you can leverage the use of 'OrderedDict' to give an indexing scheme to your dictionaries. It is seldom used, but handy.
That being said, dictionaries in python3.6 are insertion ordered :
More on that here :
Are dictionaries ordered in Python 3.6+?
d = {'animal': ['cat', 'dog', 'kangaroo', 'monkey'], 'flower': ['hibiscus', 'sunflower', 'rose']}
for key, value in d.items():
for element in value:
if element is 'dog':
print(value)
does this help? or, you want to print index of key in dictionary?

check dictionary for doubled keys [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to raise error if duplicates keys in dictionary
I was recently generating huge dictionaries with hundreds of thousands of keys (such that noticing a bug by looking at them wasn't feasible). They were syntactically correct, yet there was a bug somewhere. It boiled down to "duplicate keys":
{'a':1, ..., 'a':2}
this code compiles fine and I could not figure out why a key has value of 2 as I expected 1. The problem is obvious now.
The question is how I can prevent that in the future. I think this is impossible within python. I used
grep "'.*'[ ]*:" myfile.py | sort | uniq -c | grep -v 1
which is not bulletproof. Any other ideas (within python, this grep is just to illustrate what I'd tried)?
EDIT: I don't want duplicate keys, just need to spot that this occurs and edit data manually
A dict cannot contain double keys. So all you need to do is execute the code and then dump the repr() of the dict.
Another option is creating the dict items as (key, value) tuples. By storing them in a list you can easily create a dict from them and then check if the len()s of the dict/list differ.
If you need to have multiple values per key you can store the values in a list using defaultdict.
>>> from collections import defaultdict
>>> data_dict = defaultdict(list)
>>> data_dict['key'].append('value')
>>> data_dict
defaultdict(<type 'list'>, {'key': ['value']})
>>> data_dict['key'].append('second_value')
>>> data_dict
defaultdict(<type 'list'>, {'key': ['value', 'second_value']})
Are you generating a Python file containing a giant dictionary? Something like:
print "{"
for lines in file:
key, _, value = lines.partition(" ")
print " '%s': '%s',"
print "}"
If so, there's not much you can do to prevent this, as you cannot easily override the construction of the builtin dict.
Instead I'd suggest you validate the data while constructing the dictionary string. You could also generate different syntax:
dict(a = '1', a = '2')
..which will generate a SyntaxError if the key is duplicated. However, these are not exactly equivalent, as dictionary keys are a lot more flexible than keyword-args (e.g {123: '...'} is valid, butdict(123 = '...')` is an error)
You could generate a function call like:
uniq_dict([('a', '...'), ('a', '...')])
Then include the function definition:
def uniq_dict(values):
thedict = {}
for k, v in values:
if k in thedict:
raise ValueError("Duplicate key %s" % k)
thedict[k] = v
return thedict
You don't say or show exactly how you're generating the dictionary display you have where the duplicate keys are appearing. But that is where the problem lies.
Instead of using something like {'a':1, ..., 'a':2} to construct the dictionary, I suggest that you use this form: dict([['a', 1], ..., ['a', 2]]) which will create one from a supplied list of [key, value] pairs. This approach will allow you to check the list of pairs for duplicates before passing it to dict() to do the actual construction of the dictionary.
Here's an example of one way to check the list of pairs for duplicates:
sample = [['a', 1], ['b', 2], ['c', 3], ['a', 2]]
def validate(pairs):
# check for duplicate key names and raise an exception if any are found
dups = []
seen = set()
for key_name,val in pairs:
if key_name in seen:
dups.append(key_name)
else:
seen.add(key_name)
if dups:
raise ValueError('Duplicate key names encountered: %r' % sorted(dups))
else:
return pairs
my_dict = dict(validate(sample))

Multiple keys per value

Is it possible to assign multiple keys per value in a Python dictionary. One possible solution is to assign value to each key:
dict = {'k1':'v1', 'k2':'v1', 'k3':'v1', 'k4':'v2'}
but this is not memory efficient since my data file is > 2 GB. Otherwise you could make a dictionary of dictionary keys:
key_dic = {'k1':'k1', 'k2':'k1', 'k3':'k1', 'k4':'k4'}
dict = {'k1':'v1', 'k4':'v2'}
main_key = key_dict['k2']
value = dict[main_key]
This is also very time and effort consuming because I have to go through whole dictionary/file twice. Is there any other easy and inbuilt Python solution?
Note: my dictionary values are not simple string (as in the question 'v1', 'v2') rather complex objects (contains different other dictionary/list etc. and not possible to pickle them)
Note: the question seems similar as How can I use both a key and an index for the same dictionary value?
But I am not looking for ordered/indexed dictionary and I am looking for other efficient solutions (if any) other then the two mentioned in this question.
What type are the values?
dict = {'k1':MyClass(1), 'k2':MyClass(1)}
will give duplicate value objects, but
v1 = MyClass(1)
dict = {'k1':v1, 'k2':v1}
results in both keys referring to the same actual object.
In the original question, your values are strings: even though you're declaring the same string twice, I think they'll be interned to the same object in that case
NB. if you're not sure whether you've ended up with duplicates, you can find out like so:
if dict['k1'] is dict['k2']:
print("good: k1 and k2 refer to the same instance")
else:
print("bad: k1 and k2 refer to different instances")
(is check thanks to J.F.Sebastian, replacing id())
Check out this - it's an implementation of exactly what you're asking: multi_key_dict(ionary)
https://pypi.python.org/pypi/multi_key_dict
(sources at https://github.com/formiaczek/python_data_structures/tree/master/multi_key_dict)
(on Unix platforms it possibly comes as a package and you can try to install it with something like:
sudo apt-get install python-multi-key-dict
for Debian, or an equivalent for your distribution)
You can use different types for keys but also keys of the same type. Also you can iterate over items using key types of your choice, e.g.:
m = multi_key_dict()
m['aa', 12] = 12
m['bb', 1] = 'cc and 1'
m['cc', 13] = 'something else'
print m['aa'] # will print '12'
print m[12] # will also print '12'
# but also:
for key, value in m.iteritems(int):
print key, ':', value
# will print:1
# 1 : cc and 1
# 12 : 12
# 13 : something else
# and iterating by string keys:
for key, value in m.iteritems(str):
print key, ':', value
# will print:
# aa : 12
# cc : something else
# bb : cc and 1
m[12] = 20 # now update the value
print m[12] # will print '20' (updated value)
print m['aa'] # will also print '20' (it maps to the same element)
There is no limit to number of keys, so code like:
m['a', 3, 5, 'bb', 33] = 'something'
is valid, and either of keys can be used to refer to so-created value (either to read / write or delete it).
Edit: From version 2.0 it should also work with python3.
Using python 2.7/3 you can combine a tuple, value pair with dictionary comprehension.
keys_values = ( (('k1','k2'), 0), (('k3','k4','k5'), 1) )
d = { key : value for keys, value in keys_values for key in keys }
You can also update the dictionary similarly.
keys_values = ( (('k1',), int), (('k3','k4','k6'), int) )
d.update({ key : value for keys, value in keys_values for key in keys })
I don't think this really gets to the heart of your question but in light of the title, I think this belongs here.
The most straightforward way to do this is to construct your dictionary using the dict.fromkeys() method. It takes a sequence of keys and a value as inputs and then assigns the value to each key.
Your code would be:
dict = dict.fromkeys(['k1', 'k2', 'k3'], 'v1')
dict.update(dict.fromkeys(['k4'], 'v2'))
And the output is:
print(dict)
{'k1': 'v1', 'k2': 'v1', 'k3': 'v1', 'k4': 'v2'}
You can build an auxiliary dictionary of objects that were already created from the parsed data. The key would be the parsed data, the value would be your constructed object -- say the string value should be converted to some specific object. This way you can control when to construct the new object:
existing = {} # auxiliary dictionary for making the duplicates shared
result = {}
for k, v in parsed_data_generator():
obj = existing.setdefault(v, MyClass(v)) # could be made more efficient
result[k] = obj
Then all the result dictionary duplicate value objects will be represented by a single object of the MyClass class. After building the result, the existing auxiliary dictionary can be deleted.
Here the dict.setdefault() may be elegant and brief. But you should test later whether the more talkative solution is not more efficient -- see below. The reason is that MyClass(v) is always created (in the above example) and then thrown away if its duplicate exists:
existing = {} # auxiliary dictionary for making the duplicates shared
result = {}
for k, v in parsed_data_generator():
if v in existing:
obj = existing[v]
else:
obj = MyClass(v)
existing[v] = obj
result[k] = obj
This technique can be used also when v is not converted to anything special. For example, if v is a string, both key and value in the auxiliary dictionary will be of the same value. However, the existence of the dictionary ensures that the object will be shared (which is not always ensured by Python).
I was able to achieve similar functionality using pandas MultiIndex, although in my case the values are scalars:
>>> import numpy
>>> import pandas
>>> keys = [numpy.array(['a', 'b', 'c']), numpy.array([1, 2, 3])]
>>> df = pandas.DataFrame(['val1', 'val2', 'val3'], index=keys)
>>> df.index.names = ['str', 'int']
>>> df.xs('b', axis=0, level='str')
0
int
2 val2
>>> df.xs(3, axis=0, level='int')
0
str
c val3
I'm surprised no one has mentioned using Tuples with dictionaries. This works just fine:
my_dictionary = {}
my_dictionary[('k1', 'k2', 'k3')] = 'v1'
my_dictionary[('k4')] = 'v2'

Dictionary Operations... Index / Iterate / Validate

I'd like to:
Check a key / value at position i
Check to see if key / value contains a string
delete / store in another variable either the key / value
The equivelant of this Java code:
//Some list...
ArrayList<String> example;
...
//Index into data structure
example.get(i);
//Check for some string...
if (example.get(i).contains("someText")){
somestuff;
}
//Store in some other variable
exam = example.get(i)
That's what I'm effectively trying to in Java, however I'd like to be able to do that with Python dictionarties however I'm not sure if this is possible, as I find the Python documentation rather hard to read.
Python dictionaries are implemented as hash tables, so there is no intrinsic ordering; therefore, "position i" is a totally nonsensical concept for a dict -- it's like asking for the dict entry that's most yellow, or that least resembles a llama... those concepts just don't apply to dict entries, and "position i" is just as totally inapplicable.
Where does that i come from, i.e., what's the real issue you're trying to solve? If your requirement is to iterate over the dictionary, you do that directly, without the crutch of a "numeric index". Or, if you do need to keep some specific order or other, then you don't use a dict, but rather some different data structure. If you explain exactly the purpose you're trying to address, I'm sure we can help you.
Direct translation (for an ArrayList<String>, you do not want a dictionary, you want a list):
example = ["foo", "bar", "baz"]
str = example[i]
if "someText" in str:
somestuff()
Get used to the for keyword, though, it's awesome in Python:
for str in example:
if "someText" in str:
someStuff()
Here's an example using dictionaries:
fruits = {
"apple": "red",
"orange": "orange",
"banana": "yellow",
"pear": "green"
}
for key in fruits:
if fruits[key] == "apple":
print "An apple is my favorite fruit, and it is", fruits[key]
else:
print "A", key, "is not my favorite fruit, and it is", fruits[key]
Iteration using for on a dictionary results in the keys, it's still up to you to index the item itself. As Alex pointed out, we're really off-base answering you with so little information, and it sounds like you're not well-rooted in data structures (dictionaries will probably yield a different order every time you iterate it).
Yo can do that to reproduce the same behavior that your example in Java.
# Some list
example = {} # or example = dict()
...
# Index into data estructure.
example[example.keys(i)]
# Check for some string...
if example[example.keys(i)] == 'someText' :
pass
# Store in some other variable...
exam = example[example.keys(i)]
del example[example.keys(i)]
# ...or
exam = example.pop(example.keys(i))
What's nice about Python is that you can try code interactively.
So we create a list which is like a Java List:
>>> mylist = ["python","java","ruby"]
>>> mylist
['python', 'java', 'ruby']
We can get an entry in the list via its index:
>>> mylist[0]
'python'
And use the find function to search for substrings:
>>> mylist[1].find("av")
1
>>> mylist[1].find("ub")
-1
It returns -1 if the string isn't found.
Copying an entry to a new variable is done just how you'd expect:
>>> newvalue = mylist[2]
>>> newvalue
'ruby'
Or we can create a dict which is like a Java Map, storing by key rather than index, but these work very similarly to lists in Python:
>>> mydict = { 'python':'Guido', 'java':'James', 'ruby':'Yukihiro' }
>>> mydict['java']
'James'
>>> othervalue = mydict['ruby']
>>> othervalue
'Yukihiro'
>>> mydict['python'].find('uid')
1
>>> mydict['python'].find('hiro')
-1
>>> mydict['ruby'].find('hiro')
4

Categories