Python: understanding lambda operations in a function - python

Suppose I have a function designed to find the largest Y value in a list of dictionaries.
s1 = [
{'x':10, 'y':8.04},
{'x':8, 'y':6.95},
{'x':13, 'y':7.58},
{'x':9, 'y':8.81},
{'x':11, 'y':8.33},
{'x':14, 'y':9.96},
{'x':6, 'y':7.24},
{'x':4, 'y':4.26},
{'x':12, 'y':10.84},
{'x':7, 'y':4.82},
{'x':5, 'y':5.68},
]
def range_y(list_of_dicts):
y = lambda dict: dict['y']
return y(min(list_of_dicts, key=y)), y(max(list_of_dicts, key=y))
range_y(s1)
This works and gives the intended result.
What I don't understand is the y before the (min(list_of_dicts, key=y). I know I can find the min and max with min(list_of_dicts, key=lambda d: d['y'])['y'] where the y parameter goes at the end (obviously swapping min for max).
Can someone explain to me what is happening in y(min(list_of_dicts, key=y)) with the y and the parenthetical?

y is a function, where the function is defined by the lambda statement. The function accepts a dictionary as an argument, and returns the value at key 'y' in the dictionary.
min(list_of_dicts, key=y) returns the dictionary from the list with the smallest value under key 'y'
so putting it together, you get the value at key 'y' in the dictionary from the list with the smallest value under key 'y' of all dictionaries in the list

I know I can find the min and max with min(list_of_dicts, key=lambda d: d['y'])['y'] ...
It's exactly the same as that, but the function y does the indexing. It's a bit shorter and DRYer to write it that way.
Note that named lambdas are generally bad practice, although this case isn't too bad. Best practice is to use operator.itemgetter:
y = operator.itemgetter('y')
However, you can do it better by using generator expressions to get the min/max y-values directly, instead of their containing dicts. Then the indexing only happens twice, which makes the function y practically pointless.
return min(d['y'] for d in list_of_dicts), max(d['y'] for d in list_of_dicts)

I'm declaring Abuse of Lambda. Whenever you see a lambda assigned to a variable, you need to ask why give a name to an anonymous function? And when that function lacks a clear name, why make this hard? The function could be rewritten as follows:
def get_y(d):
"""Return "y" item from collection `d`"""
return d['y']
def range_y(list_of_dicts):
return get_y(min(list_of_dicts, key=get_y)), get_y(max(list_of_dicts, key=get_y))
In fact, there is a function in the standard lib that does this, so this may be more expected
def range_y(list_of_dicts):
get_y = operator.itemgetter("y")
return get_y(min(list_of_dicts, key=get_y)), get_y(max(list_of_dicts, key=get_y))
But there is a more straight forward way to write this. itemgetter is useful as a key in the min/max searches, but only confuses things once you've selected the dicts.
def range_y(list_of_dicts):
get_y = operator.itemgetter("y")
return min(list_of_dicts, key=get_y)["y"], max(list_of_dicts, key=get_y)["y"]
But since all you care about is the min/max "y", extract those values and work with them from the beginning.
def range_y(list_of_dicts):
y_vals = [d["y"] for d in list_of_dicts]
return min(y_vals), max(y_vals)

Related

Optimize a dictionary key conditional

I would like to optimize this piece of code. I'm sure there is a way to write it in a single line:
if 'value' in dictionary:
x = paas_server['support']
else:
x = []
use dictionary get() method as:
x = dictionary.get('support', [])
if support is not a key in the dictionary, it returns second method's argument, here, an empty list.

How to use Python Decorator to change only one part of function?

I am practically repeating the same code with only one minor change in each function, but an essential change.
I have about 4 functions that look similar to this:
def list_expenses(self):
explist = [(key,item.amount) for key, item in self.expensedict.iteritems()] #create a list from the dictionary, making a tuple of dictkey and object values
sortedlist = reversed(sorted(explist, key = lambda (k,a): (a))) #sort the list based on the value of the amount in the tuples of sorted list. Reverse to get high to low
for ka in sortedlist:
k, a = ka
print k , a
def list_income(self):
inclist = [(key,item.amount) for key, item in self.incomedict.iteritems()] #create a list from the dictionary, making a tuple of dictkey and object values
sortedlist = reversed(sorted(inclist, key = lambda (k,a): (a))) #sort the list based on the value of the amount in the tuples of sorted list. Reverse to get high to low
for ka in sortedlist:
k, a = ka
print k , a
I believe this is what they refer to as violating "DRY", however I don't have any idea how I can change this to be more DRYlike, as I have two seperate dictionaries(expensedict and incomedict) that I need to work with.
I did some google searching and found something called decorators, and I have a very basic understanding of how they work, but no clue how I would apply it to this.
So my request/question:
Is this a candidate for a decorator, and if a decorator is
necessary, could I get hint as to what the decorator should do?
Pseudocode is fine. I don't mind struggling. I just need something
to start with.
What do you think about using a separate function (as a private method) for list processing? For example, you may do the following:
def __list_processing(self, list):
#do the generic processing of your lists
def list_expenses(self):
#invoke __list_processing with self.expensedict as a parameter
def list_income(self):
#invoke __list_processing with self.incomedict as a parameter
It looks better since all the complicated processing is in a single place, list_expenses and list_income etc are the corresponding wrapper functions.

Python references to references in python

I have a function that takes given initial conditions for a set of variables and puts the result into another global variable. For example, let's say two of these variables is x and y. Note that x and y must be global variables (because it is too messy/inconvenient to be passing large amounts of references between many functions).
x = 1
y = 2
def myFunction():
global x,y,solution
print(x)
< some code that evaluates using a while loop >
solution = <the result from many iterations of the while loop>
I want to see how the result changes given a change in the initial condition of x and y (and other variables). For flexibility and scalability, I want to do something like this:
varSet = {'genericName0':x, 'genericName1':y} # Dict contains all variables that I wish to alter initial conditions for
R = list(range(10))
for r in R:
varSet['genericName0'] = r #This doesn't work the way I want...
myFunction()
Such that the 'print' line in 'myFunction' outputs the values 0,1,2,...,9 on successive calls.
So basically I'm asking how do you map a key to a value, where the value isn't a standard data type (like an int) but is instead a reference to another value? And having done that, how do you reference that value?
If it's not possible to do it the way I intend: What is the best way to change the value of any given variable by changing the name (of the variable that you wish to set) only?
I'm using Python 3.4, so would prefer a solution that works for Python 3.
EDIT: Fixed up minor syntax problems.
EDIT2: I think maybe a clearer way to ask my question is this:
Consider that you have two dictionaries, one which contains round objects and the other contains fruit. Members of one dictionary can also belong to the other (apples are fruit and round). Now consider that you have the key 'apple' in both dictionaries, and the value refers to the number of apples. When updating the number of apples in one set, you want this number to also transfer to the round objects dictionary, under the key 'apple' without manually updating the dictionary yourself. What's the most pythonic way to handle this?
Instead of making x and y global variables with a separate dictionary to refer to them, make the dictionary directly contain "x" and "y" as keys.
varSet = {'x': 1, 'y': 2}
Then, in your code, whenever you want to refer to these parameters, use varSet['x'] and varSet['y']. When you want to update them use varSet['x'] = newValue and so on. This way the dictionary will always be "up to date" and you don't need to store references to anything.
we are going to take an example of fruits as given in your 2nd edit:
def set_round_val(fruit_dict,round_dict):
fruit_set = set(fruit_dict)
round_set = set(round_dict)
common_set = fruit_set.intersection(round_set) # get common key
for key in common_set:
round_dict[key] = fruit_dict[key] # set modified value in round_dict
return round_dict
fruit_dict = {'apple':34,'orange':30,'mango':20}
round_dict = {'bamboo':10,'apple':34,'orange':20} # values can even be same as fruit_dict
for r in range(1,10):
fruit_set['apple'] = r
round_dict = set_round_val(fruit_dict,round_dict)
print round_dict
Hope this helps.
From what I've gathered from the responses from #BrenBarn and #ebarr, this is the best way to go about the problem (and directly answer EDIT2).
Create a class which encapsulates the common variable:
class Count:
__init__(self,value):
self.value = value
Create the instance of that class:
import Count
no_of_apples = Count.Count(1)
no_of_tennis_balls = Count.Count(5)
no_of_bananas = Count.Count(7)
Create dictionaries with the common variable in both of them:
round = {'tennis_ball':no_of_tennis_balls,'apple':no_of_apples}
fruit = {'banana':no_of_bananas,'apple':no_of_apples}
print(round['apple'].value) #prints 1
fruit['apple'].value = 2
print(round['apple'].value) #prints 2

Python: Handling exceptions while sorting

I have a list of objects that I need to sort according to a key function. The problem is that some of the elements in my list can go "out-of-date" while the list is being sorted. When the key function is called on such an expired item, it fails with an exception.
Ideally, what I would like is a way of sorting my list with a key function such that when an error occurs upon calling the key function on an element, this element is excluded from the sort result.
My problem can be reconstructed using the following example: Suppose I have two classes, Good and Bad:
class Good(object):
def __init__(self, x):
self.x = x
def __repr__(self):
return 'Good(%r)' % self.x
class Bad(object):
#property
def x(self):
raise RuntimeError()
def __repr__(self):
return 'Bad'
I want to sort instances of these classes according to their x property. Eg.:
>>> sorted([Good(5), Good(3), Good(7)], key=lambda obj: obj.x)
[Good(3), Good(5), Good(7)]
Now, when there is a Bad in my list, the sorting fails:
>>> sorted([Good(5), Good(3), Bad()], key=lambda obj: obj.x)
... RuntimeError
I am looking for a magical function func that sorts a list according to a key function, but simply ignores elements for which the key function raised an error:
>>> func([Good(5), Good(3), Bad()], key=lambda obj: obj.x)
[Good(3), Good(5)]
What is the most Pythonic way of achieving this?
Every sorting algorithm I know doesn't throw out some values because they're outdated or something. The task of sorting algorithm is to sort the list, and sort it fast, everything else is extraneous, specific task.
So, I would write this magical function myself. It would do the sorting in two steps: first it would filter the list, leaving only Good values, and then sort the resulting list.
I did this once with a mergesort. Mergesort makes it relatively simple to eliminate no-longer-useful values.
The project I did it in is at http://stromberg.dnsalias.org/~dstromberg/equivalence-classes.html#python-3e . Feel free to raid it for ideas, or lift code out of it; it's Free as in speech (GPLv2 or later, at your option).
The sort in that code should almost do what you want, except it'll sort a list with duplicates to a list of lists, where each sublist has equal values. That part may or may not be useful to you.
I've got a more straightforward mergesort (it doesn't do the duplicate buckets thing, but it doesn't deal with dropping no-longer-good values either) at http://stromberg.dnsalias.org/svn/sorts/compare/trunk/ . The file is .m4, but don't let that fool you - it's really pure python or cython autogenerated from the same .m4 file.
Since the result of the key function can change over time, and most sorting implementations probably assume a deterministic key function, it's probably best to only execute the key function once per object, to ensure a well-ordered and crash-free final list.
def func(seq, **kargs):
key = kargs["key"]
stored_values = {}
for item in seq:
try:
value = key(item)
stored_values[item] = value
except RuntimeError:
pass
return sorted(stored_values.iterkeys(), key=lambda item: stored_values[item])
print func([Good(5), Good(3), Bad()], key=lambda obj: obj.x)
Result:
[Good(3), Good(5)]
If the list items can go from Good to Bad while sorting, then there is nothing you can do. The keys are evaluated only once before sorting, so any change in the key will be invisible to the sort function:
>>> from random import randrange
>>> values = [randrange(100) for i in range(10)]
>>> values
[54, 72, 91, 73, 55, 68, 21, 25, 18, 95]
>>> def k(x):
... print x
... return x
...
>>> values.sort(key=k)
54
72
91
73
55
68
21
25
18
95
(If the key were evaluated many times during the sort, you would see the numbers printed many times).

Python: How to traverse a List[Dict{List[Dict{}]}]

I was just wondering if there is a simple way to do this. I have a particular structure that is parsed from a file and the output is a list of a dict of a list of a dict. Currently, I just have a bit of code that looks something like this:
for i in xrange(len(data)):
for j, k in data[i].iteritems():
for l in xrange(len(data[i]['data'])):
for m, n in data[i]['data'][l].iteritems():
dostuff()
I just wanted to know if there was a function that would traverse a structure and internally figure out whether each entry was a list or a dict and if it is a dict, traverse into that dict and so on. I've only been using Python for about a month or so, so I am by no means an expert or even an intermediate user of the language. Thanks in advance for the answers.
EDIT: Even if it's possible to simplify my code at all, it would help.
You never need to iterate through xrange(len(data)). You iterate either through data (for a list) or data.items() (or values()) (for a dict).
Your code should look like this:
for elem in data:
for val in elem.itervalues():
for item in val['data']:
which is quite a bit shorter.
Will, if you're looking to decend an arbitrary structure of array/hash thingies then you can create a function to do that based on the type() function.
def traverse_it(it):
if (isinstance(it, list)):
for item in it:
traverse_it(item)
elif (isinstance(it, dict)):
for key in it.keys():
traverse_it(it[key])
else:
do_something_with_real_value(it)
Note that the average object oriented guru will tell you not to do this, and instead create a class tree where one is based on an array, another on a dict and then have a single function to process each with the same function name (ie, a virtual function) and to call that within each class function. IE, if/else trees based on types are "bad". Functions that can be called on an object to deal with its contents in its own way "good".
I think this is what you're trying to do. There is no need to use xrange() to pull out the index from the list since for iterates over each value of the list. In my example below d1 is therefore a reference to the current data[i].
for d1 in data: # iterate over outer list, d1 is a dictionary
for x in d1: # iterate over keys in d1 (the x var is unused)
for d2 in d1['data']: # iterate over the list
# iterate over (key,value) pairs in inner most dict
for k,v in d2.iteritems():
dostuff()
You're also using the name l twice (intentionally or not), but beware of how the scoping works.
well, question is quite old. however, out of my curiosity, I would like to respond to your question for much better answer which I just tried.
Suppose, dictionary looks like: dict1 = { 'a':5,'b': [1,2,{'a':100,'b':100}], 'dict 2' : {'a':3,'b':5}}
Solution:
dict1 = { 'a':5,'b': [1,2,{'a':100,'b':100}], 'dict 2' : {'a':3,'b':5}}
def recurse(dict):
if type(dict) == type({}):
for key in dict:
recurse(dict[key])
elif type(dict) == type([]):
for element in dict:
if type(element) == type({}):
recurse(element)
else:
print element
else:
print dict
recurse(dict1)

Categories