Finding the minimum value for different variables - python

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.

Related

Python two dictionaries in dictionary, increase value in specific key

I want to increase value in dictionary of a dictionary, there is a major dictionary 'a' which has two separate dictionaries: 'be' and 'ce'. I want to increase value of specific key, determined by variables like 'dist' and 'bec' but I cannot reach the key of one of the minor dictionaries:
import collections
from collections import defaultdict
a={}
be = {}
ce = {}
for z in range(1,11):
be["b_{0}".format(z)] = 0
be = collections.OrderedDict(sorted(be.items()))
for c in range(1,11):
for b in range(1,11):
ce["c_{0}_{1}".format(c,b)]= 0
ce = collections.OrderedDict(sorted(ce.items()))
for x in range(1,10):
a["a_{0}".format(x)] = be,ce
a = collections.OrderedDict(sorted(a.items()))
dist = 3
bec = 10
a["a_"+str(dist)]["b_"+str(bec)] += 1
I tried to print "a["a_"+str(dist)]["b_"+str(bec)]" but it didnt work, it only works when I print only "a["a_"+str(dist)]"
Here's the simplest possible approach:
>>> from collections import Counter
>>> a = Counter()
>>> a[(3, 'b', 10)] += 1
>>> a[(3, 'b', 10)] += 1
>>> a[(3, 'b', 10)]
2
>>> a[(3, 'b', 8)]
0
Is there any way in which this doesn't work?

OrderedDict Changing Order after Double Iterator Loop

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)

How to I assign each variable in a list, a number, and then add the numbers up for the same variables?

For example, if ZZAZAAZ is input, the sum of A would be 14 (since its placement is 3,5,6), while the sum of Z would be 14 (1 + 2 + 4 + 7).
How would I do that?
You can use a generator expression within sum :
>>> s='ZZAZAAZ'
>>> sum(i for i,j in enumerate(s,1) if j=='A')
14
For all the elements in s you could do this. Also, it would find the counts for each element in a single pass of the string s, hence it's linear in the number of elements in s.
>>> s = 'ZZAZAAZ'
>>> d = {}
>>> for i, item in enumerate(s):
... d[item] = d.get(item, 0) + i + 1
>>> print d
{'A': 14, 'Z': 14}
Furthering Kasra's idea of using enumerate, if you wanted a dictionary containing these sums you could use a dictionary comprehension, and iterate over the set of unique characters, like so:
>>> s = 'ZZAZAAZ'
>>> {let:sum(a for a,b in enumerate(s,1) if b==let) for let in set(s)}
{'Z': 14, 'A': 14}

How to convert dictionary of indices to list of 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

using FOR statement on 2 elements at once python

I have the following list of variables and a mastervariable
a = (1,5,7)
b = (1,3,5)
c = (2,2,2)
d = (5,2,8)
e = (5,5,8)
mastervariable = (3,2,5)
I'm trying to check if 2 elements in each variable exist in the master variable, such that the above would show B (3,5) and D (5,2) as being elements with at least 2 elements matching in the mastervariable. Also note that using sets would result in C showing up as matchign but I don't want to count C cause only 'one' of the elements in C are in mastervariable (i.e. 2 only shows up once in mastervariable not twice)
I currently have the very inefficient:
if current_variable[0]==mastervariable[0]:
if current_variable[1] = mastervariable[1]:
True
elif current_variable[2] = mastervariable[1]:
True
#### I don't use OR here because I need to know which variables match.
elif current_variable[1] == mastervariable[0]: ##<-- I'm now checking 2nd element
etc. etc.
I then continue to iterate like the above by checking each one at a time which is extremely inefficient. I did the above because using a FOR statement resulted in me checking the first element twice which was incorrect:
For i in a:
for j in a:
### this checked if 1 was in the master variable and not 1,5 or 1,7
Is there a way to use 2 FOR statement that allows me to check 2 elements in a list at once while skipping any element that has been used already? Alternatively, can you suggest an efficient way to do what I'm trying?
Edit: Mastervariable can have duplicates in it.
For the case where matching elements can be duplicated so that set breaks, use Counter as a multiset - the duplicates between a and master are found by:
count_a = Counter(a)
count_master = Counter(master)
count_both = count_a + count_master
dups = Counter({e : min((count_a[e], count_master[e])) for e in count_a if count_both[e] > count_a[e]})
The logic is reasonably intuitive: if there's more of an item in the combined count of a and master, then it is duplicated, and the multiplicity is however many of that item are in whichever of a and master has less of them.
It gives a Counter of all the duplicates, where the count is their multiplicity. If you want it back as a tuple, you can do tuple(dups.elements()):
>>> a
(2, 2, 2)
>>> master
(1, 2, 2)
>>> dups = Counter({e : min((count_a[e], count_master[e])) for e in count_a if count_both[e] > count_a[e]})
>>> tuple(dups.elements())
(2, 2)
Seems like a good job for sets. Edit: sets aren't suitable since mastervariable can contain duplicates. Here is a version using Counters.
>>> a = (1,5,7)
>>>
>>> b = (1,3,5)
>>>
>>> c = (2,2,2)
>>>
>>> d = (5,2,8)
>>>
>>> e = (5,5,8)
>>> D=dict(a=a, b=b, c=c, d=d, e=e)
>>>
>>> from collections import Counter
>>> mastervariable = (5,5,3)
>>> mvc = Counter(mastervariable)
>>> for k,v in D.items():
... vc = Counter(v)
... if sum(min(count, vc[item]) for item, count in mvc.items())==2:
... print k
...
b
e

Categories