Indexing a list of dictionaries for a relating value - python-2.7

I have a 4 dictionaries which have been defined into a list
dict1 = {'A':'B'}
dict2 = {'C':'D'}
dict3 = {'E':'F'}
dict4 = {'G':'H'}
list = [dict1, dict2, dict3, dict4]
value = 'D'
print (the relating value to D)
using the list of dictionaries I would like to index it for the relating value of D (which is 'C').
is this possible?
note: the list doesn't have to be used, the program just needs to find the relating value of C by going through the 4 dictionaries in one way or another.
Thanks!

You have a list of dictionaries. A straightforward way would be to loop over the list, and search for desired value using -
dict.iteritems()
which iterates over the dictionary and returns the 'key':'value' pair as a tuple (key,value). So all thats left to do is search for a desired value and return the associated key. Here is a quick code I tried. Also this should work for dictionaries with any number of key value pairs (I hope).
dict1 = {'A':'B'}
dict2 = {'C':'D'}
dict3 = {'E':'F'}
dict4 = {'G':'H'}
list = [dict1, dict2, dict3, dict4]
def find_in_dict(dictx,search_parameter):
for x,y in dictx.iteritems():
if y == search_parameter:
return x
for i in range(list.__len__()):
my_key = find_in_dict(list[i], "D")
print my_key or "No key found"
On a different note, such a usage of dictionaries is little awkward for me, as it defeats the purpose of having a KEY as an index for an associated VALUE. But anyway, its just my opinion and I am not aware of your use case. Hope it helps.

Related

Create multiple lists and store them into a dictionary Python

Here's my situation. I got two lists:
A list which comes from DF column (OS_names)
A list with the unique values of that column (OS_values)
OS_name = df['OS_name'].tolist()
OS_values = df.OS_name.unique().tolist()
I want to create several lists (one per value in OS_values) like this :
t = []
for i in range(0,len(OS_name)-1):
if OS_values[0] == OS_name[i]:
t.append(1)
else:
t.append(0)
I want to create a list per each value in OS_value, then store them into a dictionary, and at the end creating a df from my dictionary.
If you're able to insert the value as the key it would be great, but not necessary.
I read the defaultdict may be helpful but I cannot find a way to use it.
thanks for the help and have a great day!
I did it at the very end.
dict_stable_feature = dict()
for col in df_stable:
t1 = df[col].tolist()
t2 = df[col].unique().tolist()
for value in t2:
t = []
for i in range (0, len(t1)-1):
if value == t1[i]:
t.append(1)
else:
t.append(0)
cc = str(col)
vv = "_" + str(value)
cv = cc + vv
dict_stable_feature[cv] = t

How do I extract part of a tuple that's duplicate as key to a dictionary, and have the second part of the tuple as value?

I'm pretty new to Python and Qgis, right now I'm just running scripts but I my end-goal is to create a plugin.
Here's the part of the code I'm having problems with:
import math
layer = qgis.utils.iface.activeLayer()
iter = layer.getFeatures()
dict = {}
#iterate over features
for feature in iter:
#print feature.id()
geom = feature.geometry()
coord = geom.asPolyline()
points=geom.asPolyline()
#get Endpoints
first = points[0]
last = points[-1]
#Assemble Features
dict[feature.id() ]= [first, last]
print dict
This is my result :
{0L: [(355277,6.68901e+06), (355385,6.68906e+06)], 1L: [(355238,6.68909e+06), (355340,6.68915e+06)], 2L: [(355340,6.68915e+06), (355452,6.68921e+06)], 3L: [(355340,6.68915e+06), (355364,6.6891e+06)], 4L: [(355364,6.6891e+06), (355385,6.68906e+06)], 5L: [(355261,6.68905e+06), (355364,6.6891e+06)], 6L: [(355364,6.6891e+06), (355481,6.68916e+06)], 7L: [(355385,6.68906e+06), (355501,6.68912e+06)]}
As you can see, many of the lines have a common endpoint:(355385,6.68906e+06) is shared by 7L, 4L and 0L for example.
I would like to create a new dictionary, fetching the shared points as a key, and having the second points as value.
eg : {(355385,6.68906e+06):[(355277,6.68901e+06), (355364,6.6891e+06), (355501,6.68912e+06)]}
I have been looking though list comprehension tutorials, but without much success: most people are looking to delete the duplicates, whereas I would like use them as keys (with unique IDs). Am I correct in thinking set() would still be useful?
I would be very grateful for any help, thanks in advance.
Maybe this is what you need?
dictionary = {}
for i in dict:
for j in dict:
c = set(dict[i]).intersection(set(dict[j]))
if len(c) == 1:
# ok, so now we know, that exactly one tuple exists in both
# sets at the same time, but this one will be the key to new dictionary
# we need the second tuple from the set to become value for this new key
# so we can subtract the key-tuple from set to get the other tuple
d = set(dict[i]).difference(c)
# Now we need to get tuple back from the set
# by doing list(c) we get list
# and our tuple is the first element in the list, thus list(c)[0]
c = list(c)[0]
dictionary[c] = list(d)[0]
else: pass
This code attaches only one tuple to the key in dictionary. If you want multiple values for each key, you can modify it so that each key would have a list of values, this can be done by simply modifying:
# some_value cannot be a set, it can be obtained with c = list(c)[0]
key = some_value
dictionary.setdefault(key, [])
dictionary[key].append(value)
So, the correct answer would be:
dictionary = {}
for i in a:
for j in a:
c = set(a[i]).intersection(set(a[j]))
if len(c) == 1:
d = set(a[i]).difference(c)
c = list(c)[0]
value = list(d)[0]
if c in dictionary and value not in dictionary[c]:
dictionary[c].append(value)
elif c not in dictionary:
dictionary.setdefault(c, [])
dictionary[c].append(value)
else: pass
See this code :
dict={0L: [(355277,6.68901e+06), (355385,6.68906e+06)], 1L: [(355238,6.68909e+06), (355340,6.68915e+06)], 2L: [(355340,6.68915e+06), (355452,6.68921e+06)], 3L: [(355340,6.68915e+06), (355364,6.6891e+06)], 4L: [(355364,6.6891e+06), (355385,6.68906e+06)], 5L: [(355261,6.68905e+06), (355364,6.6891e+06)], 6L: [(355364,6.6891e+06), (355481,6.68916e+06)], 7L: [(355385,6.68906e+06), (355501,6.68912e+06)]}
dictionary = {}
list=[]
for item in dict :
list.append(dict[0])
list.append(dict[1])
b = []
[b.append(x) for c in list for x in c if x not in b]
print b # or set(b)
res={}
for elm in b :
lst=[]
for item in dict :
if dict[item][0] == elm :
lst.append(dict[item][1])
elif dict[item][1] == elm :
lst.append(dict[item][0])
res[elm]=lst
print res

How to sort python lists due to certain criteria

I would like to sort a list or an array using python to achive the following:
Say my initial list is:
example_list = ["retg_1_gertg","fsvs_1_vs","vrtv_2_srtv","srtv_2_bzt","wft_3_btb","tvsrt_3_rtbbrz"]
I would like to get all the elements that have 1 behind the first underscore together in one list and the ones that have 2 together in one list and so on. So the result should be:
sorted_list = [["retg_1_gertg","fsvs_1_vs"],["vrtv_2_srtv","srtv_2_bzt"],["wft_3_btb","tvsrt_3_rtbbrz"]]
My code:
import numpy as np
import string
example_list = ["retg_1_gertg","fsvs_1_vs","vrtv_2_srtv","srtv_2_bzt","wft_3_btb","tvsrt_3_rtbbrz"]
def sort_list(imagelist):
# get number of wafers
waferlist = []
for image in imagelist:
wafer_id = string.split(image,"_")[1]
waferlist.append(wafer_id)
waferlist = set(waferlist)
waferlist = list(waferlist)
number_of_wafers = len(waferlist)
# create list
sorted_list = []
for i in range(number_of_wafers):
sorted_list.append([])
for i in range(number_of_wafers):
wafer_id = waferlist[i]
for image in imagelist:
if string.split(image,"_")[1] == wafer_id:
sorted_list[i].append(image)
return sorted_list
sorted_list = sort_list(example_list)
works but it is really awkward and it involves many for loops that slow down everything if the lists are large.
Is there any more elegant way using numpy or anything?
Help is appreciated. Thanks.
I'm not sure how much more elegant this solution is; it is a bit more efficient. You could first sort the list and then go through and filter into final set of sorted lists:
example_list = ["retg_1_gertg","fsvs_1_vs","vrtv_2_srtv","srtv_2_bzt","wft_3_btb","tvsrt_3_rtbbrz"]
sorted_list = sorted(example_list, key=lambda x: x[x.index('_')+1])
result = [[]]
current_num = sorted_list[0][sorted_list[0].index('_')+1]
index = 0
for i in example_list:
if current_num != i[i.index('_')+1]:
current_num = i[i.index('_')+1]
index += 1
result.append([])
result[index].append(i)
print result
If you can make assumptions about the values after the first underscore character, you could clean it up a bit (for example, if you knew that they would always be sequential numbers starting at 1).

Subset a list of tuples by max value in Python

My question arise from this discussion. I apologize, but I was not able to add a comment to ask my question under another answer because of my level. I have this list of tuples:
my_list = [('Scaffold100019', 98310), ('Scaffold100019', 14807), ('Scaffold100425', 197577), ('Scaffold100636', 326), ('Scaffold10064', 85415), ('Scaffold10064', 94518)]
I would like to make a dictionary which stores only the max value for each key defined as the first element of the tuple:
my_dict = {'Scaffold100019': 98310, 'Scaffold100425': 197577, 'Scaffold100636': 326, 'Scaffold10064': 94518}
Starting from the Marcus Müller's answer I have:
d = {}
#build a dictionary of lists
for x,y in my_list: d.setdefault(x,[]).append(y)
my_dict = {}
#build a dictionary with the max value only
for item in d: my_dict[item] = max(d[item])
In this way I reach my goal but, is there a sleeker way to complete this task?
I suggest this solution with only one loop, quite readable:
my_dict = {}
for x,y in my_list:
if x in my_dict.keys():
my_dict [x] = max (y, my_dict [x])
else:
my_dict [x] = y
You could use collections.defaultdict.
from collections import defaultdict
d = defaultdict(int)
for key, value in my_list:
d[key] = max(d[key], value)
The above code works on your example data, but will only work in general if each key has a maximum value that is nonnegative. This is because defaultdict(int) returns zero when no value is set, so if all values for a given key are negative, the resulting max will incorrectly be zero.
If purely negative values are possible for a given key, you can make the following alteration:
d = defaultdict(lambda: -float('inf'))
With this alteration, negative infinity will be returned when a key isn't set, so negative values are no longer a concern.
Use the fact that everything is greater than None and the dictionaries get method with None as the fallback return value.
>>> d = {}
>>> for name, value in my_list:
... if value > d.get(name, None):
... d[name] = value
...
>>> d
{'Scaffold100425': 197577, 'Scaffold10064': 94518, 'Scaffold100019': 98310, 'Scaffold100636': 326}
This will work for all values and hashes at most two times per loop.

django, trying to manipulate queryset and return to template

I'm trying to perform an operation on all the elements from a single field of a model, but I'm getting an error:
list indices must be integers, not tuple
Here's my index function in views.py:
design_list = Design.objects.values_list().order_by('-date_submitted')[:10]
x=list(design_list)
for i in x:
b = list(x[i]) # ERROR RELATES TO THIS LINE
c = b[2]
b[2] = datetimeConvertToHumanReadable(c)
new_list[i] = b
return render_to_response('index.html', {
'design_list': new_list,
})
I'm sure this is a common problem, does anyone know what I'm doing wrong?
Python is not C - the for x in y loop does not loop over indices, but over the items themselves.
design_list is a list of tuples, so you can treat it as such. Tuples are immutable, therefore you'll need to create a new list. A list comprehension would probably be best.
# Create a new list of tuples
new_list = [row[:2] + (datetimeConvertToHumanReadable(row[2]),) + row[3:]
for row in x]
However, it doesn't seem like you really need to use tuples, since you were confused by the error. If this is the case, then don't use values_list (which returns tuples), but just use order_by, and reference the field directly (I'll assume it's called date_submitted).
design_list = Design.objects.order_by('-date_submitted')[:10]
x=list(design_list)
for row in x:
row.date_submitted = datetimeConvertToHumanReadable(row.date_submitted)
return render_to_response('index.html', {
'design_list': x,
})
for i in x: iterates over the values of x, not the indices. Without analyzing the intent behind the code (and the proper use of QuerySets), the line could be changed to:
b = list(i)
to avoid this particular error.