Breaking down list of list into dictionaries - python

I have a list of list, s, that is the result of querying a database on Fruit, item[0] is the name of the fruit, item[1] is the whether or not the fruit has seeds, and item[2] is whether or not it's edible.
s = [['Apple','Yes','Edible'], ['Watermellon','Yes','Yes']]
As my actual list is much bigger, I would like a really easy way to reference/return these values. For example, print my_dict['Apple']['Seeds'] would yield Yes
I think my best option would be to create a dictionary, but am looking for recommendations on if this is a good method and how to do this.
I started writing some code but am not sure how to get the second set of headers in place, so my example uses an index instead.
my_dict = {t[0]:t[1:] for t in s}
print my_dict['Apple'][0]

fruit_map = {
fruit: {'Seeds': seeds, 'Edible': edible} for fruit, seeds, edible in s}

If the second set of keys never changes, it would be better to define a proper object with fields. This might seem overkill or to verbose, but there is always collections.namedtuple to help.
namedtuple creates a new class from a list of field names. That class also supports being initialized by a list. To use your example:
import collections
Fruit = collections.namedtuple('Fruit', ['name', 'seeds', 'edible'])
This way, you can easily create Fruit objects from a list:
f = Fruit('Apple', True, False)
# Or, if you already have a list with the values
params = ['Apple', True, False]
f = Fruit(*params)
print f.seed
So you can create a list of fruits in a very easy way:
s = [['Apple','Yes','Edible'], ['Watermellon','Yes','Yes']]
fruits = [Fruit(*l) for l in s]
You really need to have a dictionary indexed by a certain field, it is not much different:
s = [['Apple','Yes','Edible'], ['Watermellon','Yes','Yes']]
fruit_dict = {l[0]: Fruit(*l) for l in s}
print(fruit_dict['Apple'].seeds)
namedtuples can be very convenient when transforming lists of values into more easy to use objects (such as when reading a CSV file, which is a case very similar to what you are asking).

import copy
def list_to_dict(lst):
local = copy.copy(lst) # copied lst to local
fruit = [i.pop(0) for i in local] # get fruit names
result = {}
for i in range(len(local)):
result[fruit[i]] = local[i]
return result
This returns the dictionary you want.

Related

How to reset value of multiple dictionaries elegantly in python

I am working on a code which pulls data from database and based on the different type of tables , store the data in dictionary for further usage.
This code handles around 20-30 different table so there are 20-30 dictionaries and few lists which I have defined as class variables for further usage in code.
for example.
class ImplVars(object):
#dictionary capturing data from Asset-Feed table
general_feed_dict = {}
ports_feed_dict = {}
vulns_feed_dict = {}
app_list = []
...
I want to clear these dictionaries before I add data in it.
Easiest or common way is to use clear() function but this code is repeatable as I will have to write for each dict.
Another option I am exploring is with using dir() function but its returning variable names as string.
Is there any elegant method which will allow me to fetch all these class variables and clear them ?
You can use introspection as you suggest:
for d in filter(dict.__instancecheck__, ImplVars.__dict__.values()):
d.clear()
Or less cryptic, covering lists and dicts:
for obj in ImplVars.__dict__.values():
if isinstance(obj, (list, dict)):
obj.clear()
But I would recommend you choose a bit of a different data structure so you can be more explicit:
class ImplVars(object):
data_dicts = {
"general_feed_dict": {},
"ports_feed_dict": {},
"vulns_feed_dict": {},
}
Now you can explicitly loop over ImplVars.data_dicts.values and still have other class variables that you may not want to clear.
code:
a_dict = {1:2}
b_dict = {2:4}
c_list = [3,6]
vars_copy = vars().copy()
for variable, value in vars_copy.items():
if variable.endswith("_dict"):
vars()[variable] = {}
elif variable.endswith("_list"):
vars()[variable] = []
print(a_dict)
print(b_dict)
print(c_list)
result:
{}
{}
[]
Maybe one of the easier kinds of implementation would be to create a list of dictionaries and lists you want to clear and later make the loop clear them all.
d = [general_feed_dict, ports_feed_dict, vulns_feed_dict, app_list]
for element in d:
element.clear()
You could also use list comprehension for that.

Build a List of Tuples from a Dict

I have a list y of keys from a dictionary that is derived from a call to the Google Places API.
I would like to build a list of tuples for each point of interest:
lst = []
for i in range(len(y)):
lst.append((y[i]['name'], y[i]['formatted_address'], y[i]['opening_hours']['open_now'], y[i]['rating']))
This works if the field is in the list and I receive a list of results that look like the one below, which is exactly what I want:
("Friedman's", '1187 Amsterdam Ave, New York, NY 10027, USA', True, 4.2)
However, the script throws an error if a desired field is not in the list y. How can I build a list of tuples that checks whether the desired field is in y before building the tuple?
Here's what I've tried:
for i in range(len(y)):
t = ()
if y[i]['name']:
t = t + lst.append(y[i]['name'])
if y[i]['formatted_address']:
t = t + lst.append(y[i]['formatted_address'])
if y[i]['opening_hours']['open_now']:
t = t + lst.append(y[i]['opening_hours']['open_now'])
if y[i]['rating']:
t = t + lst.append(y[i]['rating'])
lst.append(t)
However, this doesn't work and seems very inelegant. Any suggestions?
This list comprehension uses default values when one of the keys is not present (using dict.get()). I added variables so you can set the desired default values.
default_name = ''
default_address = ''
default_open_now = False
default_rating = 0.0
new_list = [
(
e.get('name', default_name),
e.get('formatted_address', default_address),
e.get('opening_hours', {}).get('open_now', default_open_now),
e.get('rating', default_rating),
)
for e in y]
For a start, you should almost never loop over range(len(something)). Always iterate over the thing directly. That goes a long way to making your code less inelegant.
For the actual issue, you could loop over the keys and only add the item if it is in the dict. That gets a bit more complicated with your one element that is a nested lookup, but if you take it out then your code just becomes:
for item in y:
lst.append(tuple(item[key] for key in ('name', 'formatted_address', 'opening_hours', 'rating') if key in item))
You can use the get feature from dict.
y[i].get('name')
if y[i] has key 'name' returns the value or None. For nested dicts, use default value from get.
y[i].get('opening_hours', {}).get('open_now')
For data structure, I recommend to keep it as an dict, and add dicts to an list.
lst = []
lst.append({'name': "Friedman's", "address": '1187 Amsterdam Ave, New York, NY 10027, USA'})
Try this:
for i in y:
lst.append((v for k,v in i.items()))
you can use the keys method to find the keys in a dict. In your case:
lst=[]
fields = ('name', 'formatted_address', 'opening_hours' 'open_now', 'rating')
for i in range(len(y)):
data = []
for f in fields:
if f in y[].keys():
data.append(y[i][f])
else:
data.append(None)
lst.append(set(data))
note that you can also get all the key, value pairs in a dict using the items() method. That would actually simply the code a bit. To make it even better, itterate over the set, rather than calling len(set) to:
lst=[]
fields = ('name', 'formatted_address', 'opening_hours' 'open_now', 'rating')
for i in y:
data = []
for key, value in i.items():
if key in fields:
data.append(value)
else:
data.append(None)
lst.append(set(data))

Can you create dictionaries with just a single function?

As a total beginner I'm quite proud of this function. Although I believe there's probably an easier, more pythonic way of doing the exact same thing:
Genes = ['Gen1', 'Gen2', 'Gen3']
Mutations = ['Gen1.A', 'Gen1.B', 'Gen2.A', 'Gen3.A', 'Gen3.B', 'Gen3.C']
def RawDict(keys, values):
dictKeys = []
dictValues = []
for key in keys:
keyVal = []
for value in values:
if value.find(key) == -1:
pass
else:
keyVal.append(value)
dictKeys.append(key)
dictValues.append(keyVal)
return zip(dictKeys, dictValues)
GenDict = dict(RawDict(Genes, Mutations))
print(GenDict)
The function above is a rather overcomplicated (I think) way of putting several values (mutations) within keys (genes). However I was wondering if I could tweak this so I could get a dictionary by just doing this:
dict(GenDict, Genes, Mutations)
print(GenDict)
My struggle involves that when I use dict within the function, this won't work:
Genes = ['Gen1', 'Gen2', 'Gen3']
Mutations = ['Gen1.A', 'Gen1.B', 'Gen2.A', 'Gen3.A', 'Gen3.B', 'Gen3.C']
def fullDict(dictName, keys, values):
dictKeys = []
dictValues = []
for key in keys:
keyVal = []
for value in values:
if value.find(key) == -1:
pass
else:
keyVal.append(value)
dictKeys.append(key)
dictValues.append(keyVal)
dictName = dict(RawDict(Genes, Mutations))
fullDict(GenDict, Genes, Mutations)
print(GenDict)
The above just won't work as GenDict is not defined.
From what I understand, you want to move from this:
gen_dict = make_dictionary(genes, mutations)
to this:
make_dictionary(gen_dict, genes, mutations)
where the make_dictionary function "creates" the variable gen_dict.
Unfortunately, this isn't really how variables work. If you want to define a variable called GenDict, the way to do this is to use GenDict = .... You could do something like this:
gen_dict = {}
fill_dictionary(gen_dict, genes, mutations)
This creates a variable called gen_dict and assigns it to a new, empty dictionary. Your function would then go through and add things to that dictionary:
def fill_dictionary(d, genes, mutations):
for g in genes:
d[g] = [m for m in mutations if m.startswith(g)]
But calling a function cannot cause a new variable to appear in the caller's scope. (This is not completely true, because of globals(), but for most intents and purposes, it is.)
(By the way, there is a one-liner that will create the dictionary: dictionary = { g : [m for m in mutations if m.startswith(g+".")] for g in genes }. Search for list comprehensions and dictionary comprehensions on Google or StackOverflow -- they are amazing!)
I am assuming that you want the "Gen"s to be stored by the numerical value that it contains.
Genes = ['Gen1', 'Gen2', 'Gen3']
Mutations = ['Gen1.A', 'Gen1.B', 'Gen2.A', 'Gen3.A', 'Gen3.B', 'Gen3.C']
the_dict = {i:[] for i in Genes}
for i in Mutations:
new_val = i.split(".")
the_dict[new_val[0]].append(i)
print(the_dict)
Output:
{'Gen2': ['Gen2.A'], 'Gen3': ['Gen3.A', 'Gen3.B', 'Gen3.C'], 'Gen1': ['Gen1.A', 'Gen1.B']}
I assume you have a background in programming in some other language than Python; a language that lets you change function parameters. Well, Python does not. The problem is not with the use of dict, but rather with the fact that you're assigning to a function parameter. This will not have an effect outside the function. What you want to do is probably this:
def fullDict(keys, values):
return { key: [ value for value in values if key in value] for key in keys }
print(fullDict(Genes, Mutations))

Pythonic way to get the index of element from a list of dicts depending on multiple keys

I am very new to python, and I have the following problem. I came up with the following solution. I am wondering whether it is "pythonic" or not. If not, what would be the best solution ?
The problem is :
I have a list of dict
each dict has at least three items
I want to find the position in the list of the dict with specific three values
This is my python example
import collections
import random
# lets build the list, for the example
dicts = []
dicts.append({'idName':'NA','idGroup':'GA','idFamily':'FA'})
dicts.append({'idName':'NA','idGroup':'GA','idFamily':'FB'})
dicts.append({'idName':'NA','idGroup':'GB','idFamily':'FA'})
dicts.append({'idName':'NA','idGroup':'GB','idFamily':'FB'})
dicts.append({'idName':'NB','idGroup':'GA','idFamily':'FA'})
dicts.append({'idName':'NB','idGroup':'GA','idFamily':'FB'})
dicts.append({'idName':'NB','idGroup':'GB','idFamily':'FA'})
dicts.append({'idName':'NB','idGroup':'GB','idFamily':'FB'})
# let's shuffle it, again for example
random.shuffle(dicts)
# now I want to have for each combination the index
# I use a recursive defaultdict definition
# because it permits creating a dict of dict
# even if it is not initialized
def tree(): return collections.defaultdict(tree)
# initiate mapping
mapping = tree()
# fill the mapping
for i,d in enumerate(dicts):
idFamily = d['idFamily']
idGroup = d['idGroup']
idName = d['idName']
mapping[idName][idGroup][idFamily] = i
# I end up with the mapping providing me with the index within
# list of dicts
Looks reasonable to me, but perhaps a little too much. You could instead do:
mapping = {
(d['idName'], d['idGroup'], d['idFamily']) : i
for i, d in enumerate(dicts)
}
Then access it with mapping['NA', 'GA', 'FA'] instead of mapping['NA']['GA']['FA']. But it really depends how you're planning to use the mapping. If you need to be able to take mapping['NA'] and use it as a dictionary then what you have is fine.

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