I set up an OrderedDict and perform dictionary comprehensions with different grammars, which I have simplified to a function dictcomp(fn, dictionary, key_or_value)::
x = OrderedDict(self._Median_Colors)
x = self.dictcomp(hex2color, x, 'v')
x = self.dictcomp(rgb_to_hsv, x, 'v_tuple')
At this point I am able to sort the dictionary:
x = self.dictcomp(self.sort_by_hue, x, 'v')
Everything seems to check out so far:
print x
Now I need to rename keys, so I will create a new ordered dictionary:
color_indexes = list(xrange(0, len(x.keys())))
print color_indexes
newkeys = [self.rename(color_index) for color_index in color_indexes]
print x.values()
vi = iter(x.values())
x = OrderedDict.fromkeys(newkeys);
I had no idea how to fill in the old values immediately, so I did this:
ki = iter(x.keys())
for k, v in zip(ki, vi):
#print "k:", k
print v
x[k] = tuple(v)
Checks out fine:
print x.items()
Here comes trouble:
x = self.dictcomp(hsv_to_rgb, x, 'v_tuple')
print x.items()
where dictcomp does this:
dictionary = {k: fn(*v) for k, v in dictionary.items()}
where fn=hsv_to_rgb, dictionary=x
Now, I have:
[('Blue', (0.9764705882352941, 0.5529411764705883, 0.0)), ....
instead of the expected:
[('Red', (0.4745098039215686, 0.7372549019607844, 0.23137254901960794)), ....
The keys are the same, but the values have changed. I am guessing that the insertion order was somehow affected. How did this happen and how can I keep the order of keys in the dictionary?
The problem is because of
for i, j in zip([4, 5, 6], [1, 2, 3]):
print i
print j
Results in the column:
4 1 5 2 6 3
It turns out that zip acts as a zipper if using two iterators.
The fix is to get the keyword-value as an iterable tuple:
for i in zip([4, 5, 6], [1, 2, 3]):
print i
Returns
(4, 1)
(5, 2)
(6, 3)
Related
If i am doing some math functions for different variables for example:
a = x - y
b = x**2 - y**2
c = (x-y)**2
d = x + y
How can i find the minimum value out of all the variables. For example:
a = 4
b = 7
c = 3
d = 10
So the minimum value is 3 for c. How can i let my program do this.
What have i thought so far:
make a list
append a,b,c,d in the list
sort the list
print list[0] as it will be the smallest value.
The problem is if i append a,b,c,d to a list i have to do something like:
lst.append((a,b,c,d))
This makes the list to be -
[(4,7,3,10)]
making all the values relating to one index only ( lst[0] )
If possible is there any substitute to do this or any way possible as to how can i find the minimum!
LNG - PYTHON
Thank you
You can find the index of the smallest item like this
>>> L = [4,7,3,10]
>>> min(range(len(L)), key=L.__getitem__)
2
Now you know the index, you can get the actual item too. eg: L[2]
Another way which finds the answer in the form(index, item)
>>> min(enumerate(L), key=lambda x:x[1])
(2, 3)
I think you may be going the wrong way to solving your problem, but it's possible to pull values of variable from the local namespace if you know their names. eg.
>>> a = 4
>>> b = 7
>>> c = 3
>>> d = 10
>>> min(enumerate(['a', 'b', 'c', 'd']), key=lambda x, ns=locals(): ns[x[1]])
(2, 'c')
a better way is to use a dict, so you are not filling your working namespace with these "junk" variables
>>> D = {}
>>> D['a'] = 4
>>> D['b'] = 7
>>> D['c'] = 3
>>> D['d'] = 10
>>> min(D, key=D.get)
'c'
>>> min(D.items(), key=lambda x:x[1])
('c', 3)
You can see that when the correct data structure is used, the amount of code required is much less.
If you store the numbers in an list you can use a reduce having a O(n) complexity due the list is not sorted.
numbers = [999, 1111, 222, -1111]
minimum = reduce(lambda mn, candidate: candidate if candidate < mn else mn, numbers[1:], numbers[0])
pack as dictionary, find min value and then find keys that have matching values (possibly more than one minimum)
D = dict(a = 4, b = 7, c = 3, d = 10)
min_val = min(D.values())
for k,v in D.items():
if v == min_val: print(k)
The buiit-in function min will do the trick. In your example, min(a,b,c,d) will yield 3.
I have a graph with 2 kinds of nodes- 'Letter nodes' (L) and 'Number nodes' (N). I have 2 dictionaries, one shows edges from L to N and the other shows edges from N to L.
A = {0:(b,), 1:(c,), 2:(c,), 3:(c,)}
B = {a:(3,), b:(0,), c:(1,2,3)}
A key,value pair c:(1,2,3) means there are edges from c to 1,2,3 (3 edges)
I want to merge these to one dictionary C so that the result is a new dictionary:
C = {(0,): (b,), (1, 2, 3): (a, c)}
or
C = {(b,):(0,), (a, c):(1, 2, 3)}
In the resulting dictionary I want the letter nodes and numerical nodes to be on separate sides of keys and values. I don't care which is the key or value just need them separated. How can I go about solving this efficiently?
CLARIFICATION: this of a graph with 2 types of nodes - number nodes, and letter nodes. the dictionary C says from letter nodes (a,c) you can reach the number nodes (1,2,3) i.e a->3->c->1, a->3->c->2 thus you can get to 1,2,3 from a. EVEN THOUGH THERE IS NO DIRECT EDGE FROM a to 2 or a to 1.
According to your statement, I guess you are trying to find a graph algorithms.
import itertools
def update_dict(A, result): #update vaules to the same set
for k in A:
result[k] = result.get(k, {k}).union(set(A[k]))
tmp = None
for i in result[k]:
tmp = result.get(k, {k}).union(result.get(i, {i}))
result[k] = tmp
for i in result[k]:
result[i] = result.get(i, {i}).union(result.get(k, {k}))
A = {0:('b',), 1:('c',), 2:('c',), 3:('c',)}
B = {'a':(3,), 'b':(0,), 'c':(1,2,3)}
result = dict()
update_dict(A, result)
update_dict(B, result)
update_dict(A, result) #update to fix bugs
update_dict(B, result)
k = sorted([sorted(list(v)) for v in result.values()])
k = list( k for k, _ in itertools.groupby(k)) #sort and remove dumplicated set
final_result = dict()
for v in k: #merge the result as expected
final_result.update({tuple([i for i in v if isinstance(i, int)]):tuple([i for i in v if not isinstance(i, int)])})
print final_result
#output
{(0,): ('b',), (1, 2, 3): ('a', 'c')}
So I'm not sure if this is the most efficient way of doing this at this point, but it works:
A = {0:('b',), 1:('c',), 2:('c',), 3:('c',)}
B = {'a':(3,), 'b':(0,), 'c':(1,2,3)}
# Put B in the same form as A
B_inv = {}
for k, v in B.items():
for i in v:
if B_inv.get(i) is not None:
B_inv[i] = B_inv[i].union(k)
else:
B_inv[i] = set(k)
B_inv = {k: tuple(v) for k, v in B_inv.items()}
AB = set(B_inv.items() + A.items()) # get AB as merged
This gets you the merged dictionaries. From here:
new_dict = {}
for a in AB:
for i in a[1]:
if new_dict.get(i) is not None:
new_dict[i] = new_dict[i].union([a[0]])
else:
new_dict[i] = set([a[0]])
# put in tuple form
new_dict = {tuple(k): tuple(v) for k,v in new_dict.items()}
This gives me:
{('a',): (3,), ('b',): (0,), ('c',): (1, 2, 3)}
Basically, I'm relying on the mutability of sets and their built-in functionality of eliminating duplicates to try to keep the number of loops through each dictionary to a minimum. Unless I missed something, this should be in linear time.
From here, I need to do comparison, and relying on sets again to prevent me from needing to do a worst-case pairwise comparison of every single element.
merge_list = []
for k, v in new_dict.items():
matched = False
nodeset = set([k[0]]).union(v)
for i in range(len(merge_list)):
if len(nodeset.intersection(merge_list[i])) != 0:
merge_list[i] = merge_list[i].union(nodeset)
matched = True
# did not find shared edges
if not matched:
merge_list.append(nodeset)
Finally, turn it into the form with a single "layer" and tuples.
C = {}
for item in merge_list:
temp_key = []
temp_val = []
for i in item:
if str(i).isalpha():
temp_key.append(i)
else:
temp_val.append(i)
C[tuple(temp_key)] = tuple(temp_val)
C gives me {('a', 'c'): (1, 3, 2), ('b',): (0,)}.
try this:
c = a.copy()
c.update(b)
I have the following code which will compare the two dictionaries b and c and create a third one from them called d which contains the product of comparing b to c and taking the highest one:
b = {1:0,2:0,3:0,4:0,5:0}
c = {1:1,4:4,5:5}
d={k:c[k] if k in c and c[k]>b[k] else v for k,v in b.items()}
However, because dictionaries are not sorted I have had to use the following syntax to convert b and c into tuples, before comparing them, so that they are in the right order:
b = sorted(b.iteritems())
c = sorted(c.iteritems())
This produces an output of:
b = [(1,0),(2,0),(3,0),(4,0),(5,0)]
c = [(1,1),(4,4),(5,5)]
However I am now unsure of how I could compare the two tuples and produce an output that looks like this:
d = [(1,1),(2,0),(3,0),(4,4),(5,5)]
There does not seem to be a tuple comprehension available in Python 2.7, unless I have not been looking for answers in the right places.
Can anyone assist?
You can add a one liner (the last line) to the upper code snippet:
b = {1:0,2:0,3:0,4:0,5:0}
c = {1:1,4:4,5:5}
d={k:c[k] if k in c and c[k]>b[k] else v for k,v in b.items()}
print [(k, v) for k, v in d.items()] # [(1, 1), (2, 0), (3, 0), (4, 4), (5, 5)]
Why can't you just sort the items of d?
b = {1:0, 2:0, 3:0, 4:0, 5:0}
c = {1:1, 4:4, 5:5}
d = {k: c[k] if k in c and c[k] > b[k] else v for k, v in b.items()}
sorted(d.items())
I suppose this implies that you know the keys of c are a subset of the keys in b. If this isn't true, you need to get the union of the keys and them compare the values from each dict:
b = {1:0, 2:0, 3:0, 5:0}
c = {1:1, 4:4, 5:5} # note, 4 not in "b"
ninf = -float('inf') # some value smaller than all others.
all_keys = b.viewkeys() | c # Union of keys.
result = [(k, max(b.get(k, ninf), c.get(k, ninf))) for k in sorted(all_keys)]
print(result) # [(1, 1), (2, 0), (3, 0), (4, 4), (5, 5)]
You can do the same thing, but in the order of the sorted keys of b, and make a tuple on the fly
d=tuple(
(k , (c[k] if k in c and c[k]>b[k] else b[k]) )
for k in sorted(b.keys()) )
or some might prefer
d=tuple(
(k , max(b[k],c.get(k,minus_inf)) )
for k in sorted(b.keys()) )
... if a suitable minus_inf exists which is less than all possible b[k]. For numbers, None works so you could use
d=tuple(
(k , max(b[k],c.get(k)) ) # note, max( x,None)==x here
for k in sorted(b.keys()) )
Say you have a dictionary listing the indices where each unique value appear. For example say you alphabet is just a and b then this dictionary will look something like: d = {'a': [1, 2, 6], 'b': [3, 7]}. I would like to convert it to the raw list which shows at the right index the right value, such that in the last example, l = ['a','a','b',None,None,'a',b']. I prefer an easy small solution rather than one which has tedious for loops. Thank!
Obviously doing this without for loops is a terrible idea, because the easiest way is (it's not perfect, but it does the job):
r = {}
for key, value in d.items():
for element in value:
r[element] = key
l = [r.get(i) for i in xrange(1, max(r) + 1)]
But if you REALLY want to know how to do this without any for then have a look:
m = {}
i = 0
d_keys = d.keys()
max_value = 0
while i < len(d):
d_i = d[d_keys[i]]
j = 0
while j < len(d_i):
d_i_j = d_i[j]
if max_value < d_i_j:
max_value = d_i_j
m[d_i_j] = d_keys[i]
j += 1
i += 1
l = []
i = 1
while i <= max_value:
l.append(m.get(i))
i += 1
It's quite easy, isn't it?
I don't know why you need that, but here is a dirty answer, without loops.
d = {'a': [1, 2, 6], 'b': [3, 7]}
map(lambda x: x[0] if x else None, map(lambda x: filter(lambda l: x in d[l], d), range(1, max(reduce(lambda x, y: x+y, map(lambda x:d[x], d)))+1)))
d.keys()
keys()
Return a copy of the dictionary’s list of keys. See the note for dict.items()
from Python Docs
I have a dictionary dict={14:1, 15:2, 16:4, 11:5, 20:1,22:5,25:2...} in python
How can I obtain a final result in any data structure(dictionary or something else) which looks like:
Final= [10-15:8, 16-20:5, 21-25:7....] or at least can sum up the values for keys falling under certain ranges of let say 10-15, 15-20 etc.
The final goal is to containerize data for building histogram or bar graphs.
from itertools import groupby
my_dict = {14:1, 15:2, 16:4, 11:5, 20:1, 22:5, 25:2}
key_fn, result = lambda (x, _): x / 5 + 1 if x % 5 else x / 5, {}
for item, grp in groupby(sorted(my_dict.items(), key = key_fn), key_fn):
result[((item - 1) * 5 + 1, item * 5)] = sum(count for _, count in grp)
print result
Output
{(11, 15): 8, (21, 25): 7, (16, 20): 5}
What about using modulo and defaultdict
from collections import defaultdict
output = defaultdict(int)
input = {14:1, 15:2, 16:4, 11:5, 20:1, 22:5, 25:2}
group = 5
for key, value in input.iteritems():
output[key - key % group] += value
>> {25: 2, 10: 6, 20: 6, 15: 6}
I would suggest you to use numpy.histogram after flattening your dictionary
Implementation
import numpy as np
from itertools import chain
data={14:1, 15:2, 16:4, 11:5, 20:1,22:5,25:2}
#Flattern your dictionary
data = list(chain.from_iterable([k]*v for k, v in data.items()))
#Define your bins
bins = [10,16,21,25]
And finally generate the histogram
hist = np.histogram(data, bins=bins)[0]
Output
for r in zip(bins, bins[1:], hist):
print "{}-{}:{}".format(*r)
10-16:8
16-21:5
21-25:7
Here's what I got:
newdict = {}
for key, value in dict.items:
mapped_key = key / 5 # if python 2
mapped key = key // 5 # if python 3
newdict.setdefault(mapped_key, 0)
newdict[mapped_key] += value
Now someone will go and one-up me with a single-line crazy map lambda dictionary comprehenshion thing.