python for loop expression of iterator - python

I have a for loop in which I use the iterator always in the same manner, like this
for dict in mylist:
var = dict['prop']
var2 = f( dict['prop'] )
...
This is clumsy. The only alternatives I can think of:
local variable
wrapping the mylist in a list comprehension. But that seems overkill and is probably inefficient
Any better way?

One map call would work to give you a list of tuples of values:
listOfTuples = map(lambda x: (dict['prop'], f(dict['prop']), myList)
Or if you want two separate lists of values:
[varList, var2List] = zip(*zip(listOfTuples))

Related

A list of a lists into a single string

Suppose I have a list of lists say
A = [[1,1,1,1],[2,2,2,2]]
and I want to create two strings from that to be
'1111'
'2222'
How would we do this in python?
Maybe list comprehension:
>>> A = [[1,1,1,1],[2,2,2,2]]
>>> l=[''.join(map(str,i)) for i in A]
>>> l
['1111', '2222']
>>>
Now you've got it.
This is pretty easily done using join and a list comprehension.
A = [[1,1,1,1],[2,2,2,2]]
a_strings = [''.join(map(str, sub_list)) for sublist in A]
See, join() takes a list of strings and makes a string concatenating all the substrings and the list comprehension I used just loops through them all. Above I combined the 2 together.
On a second thought
map() is actually deemed more efficient (when not using lambda.. etc) and for SOME more readable. I'll just add an approach using map instead of a comprehension.
a_strings = map(''.join(), map(str, A))
This first takes the inner map and makes all the ints > strs then joins all the strs together for every sub-list.
Hopefully this makes things a bit more chewable for ya, each method is close to equivalent such that for this case you could consider them style choices.

Python - Creating a list of dictionaries

I wanted to create a list of dictionaries in python. The usual way of creating a list worked for me. That is mylist = [{1:1},{2:2}]
However, when I tried creating it using a comprehension over range() function, mylist = [a:a for a in range(10)] I get syntax error.
But to my surprise, if I construct a set in the same manner, it works as expected. myset = {a:a for a in range(10)}
May I know why this is so? I am using Python3
I think you want something like this:
mylist = [{a:a} for a in range(10)]
You forgot about { and }.
In the second example, your myset is a dict, not a set:
In [8]: type(myset)
Out[8]: dict
In this example, { and } denote dictionary comprehension, not set comprehension.
You're missing a dictionary creation in your list comprehension:
mylist = [{a:a} for a in range(10)]

Using Lambda with lists

I am trying to check if a string object is in a list. Simply written as:
if str in list:
The problem I am facing is that this list, is not a list of strings, but a list of tables. I understand that nothing is going to happen if I do this comparison directly. What I would like to do is access an attribute of each of these tables called 'Name'.
I could create a new list, and do my comparison against that:
newList = []
for i in list:
newList.append(i.Name)
But as I am still a newbie, I am curious about Lambda's and wondered if it would be possible to implement that instead?
something like (... but probably nothing like):
if str in list (lambda x: x.Name):
You can write
if str in [x.Name for x in list]
Or more lazily,
if str in (x.Name for x in list)
In the latter (with parens) it builds a generator, while in the former (with brackets), it builds first the full list.
Lambdas pretty much doesn't needed here. You can just check it directly:
for table in my_list:
if string in table.Name:
#do stuff
Or using list comprehension, if you want it that way:
if string in [table.Name for table in my_list]:
#do interesting stuff
More efficiently, as #Tim suggested, use a generator expression:
if string in (table.Name for table in my_list):
But if you insist in using lambdas:
names = map(lambda table: table.Name, my_list)
if string in names:
#do amazing stuff!
Here's a little demo:
>>> class test():
def __init__(self, name):
self.Name = name
>>> my_list = [test(n) for n in name]
>>> l = list(map(lambda table: table.Name, my_list)) #converted to list, it's printable.
>>> l
['a', 'b', 'c']
Also, avoid using names of built in functions such as str, list for variable names. It will override them!
Hope this helps!
I guess you're looking for any:
if any(x.Name == s for x in lst):
...
If the list is not large and you need these names somewhere else, you can create a list or a set of names:
names = {x.Name for x in lst}
if s in names:
....
The lambda you wrote is already in python, and called attrgetter (in module operator):
names = map(attrgetter('Name'), lst)
Note that comprehensions are usually preferred to that.
you can use filter
>>> foo = ["foo","bar","f","b"]
>>> list(filter( lambda x:"f" in x,foo))
['foo', 'f']
update
i keep this answer because someone may come here for lambdas but for this problem #arbautjc 's answer is better.

Python list of tuples, need to unpack and clean up

Assume you have a list such as
x = [('Edgar',), ('Robert',)]
What would be the most efficient way to get to just the strings 'Edgar' and 'Robert'?
Don't really want x[0][0], for example.
Easy solution, and the fastest in most cases.
[item[0] for item in x]
#or
[item for (item,) in x]
Alternatively if you need a functional interface to index access (but slightly slower):
from operator import itemgetter
zero_index = itemgetter(0)
print map(zero_index, x)
Finally, if your sequence is too small to fit in memory, you can do this iteratively. This is much slower on collections but uses only one item's worth of memory.
from itertools import chain
x = [('Edgar',), ('Robert',)]
# list is to materialize the entire sequence.
# Normally you would use this in a for loop with no `list()` call.
print list(chain.from_iterable(x))
But if all you are going to do is iterate anyway, you can also just use tuple unpacking:
for (item,) in x:
myfunc(item)
This is pretty straightforward with a list comprehension:
x = [('Edgar',), ('Robert',)]
y = [s for t in x for s in t]
This does the same thing as list(itertools.chain.from_iterable(x)) and is equivalent in behavior to the following code:
y = []
for t in x:
for s in t:
y.append(s)
I need to send this string to another function.
If your intention is just to call a function for each string in the list, then there's no need to build a new list, just do...
def my_function(s):
# do the thing with 's'
x = [('Edgar',), ('Robert',)]
for (item,) in x:
my_function(item)
...or if you're prepared to sacrifice readability for performance, I suspect it's quickest to do...
def my_function(t):
s = t[0]
# do the thing with 's'
return None
x = [('Edgar',), ('Robert',)]
filter(my_function, x)
Both map() and filter() will do the iteration in C, rather than Python bytecode, but map() will need to build a list of values the same length of the input list, whereas filter() will only build an empty list, as long as my_function() returns a 'falsish' value.
Here is one way:
>>> [name for name, in x]
['Edgar', 'Robert']
Note the placement of the comma, which unpacks the tuple.
>>> from operator import itemgetter
>>> y = map(itemgetter(0), x)
>>> y
['Edgar', 'Robert']
>>> y[0]
'Edgar'
>>> y[1]
'Robert'

python: union keys from multiple dictionary?

I have 5 dictionaries and I want a union of their keys.
alldict = [dict1, dict2, dict3, dict4, dict5]
I tried
allkey = reduce(lambda x, y: set(x.keys()).union(y.keys()), alldict)
but it gave me an error
AttributeError: 'set' object has no attribute 'keys'
Am I doing it wrong ? I using normal forloop but I wonder why the above code didn't work.
I think #chuck already answered the question why it doesn't work, but a simpler way to do this would be to remember that the union method can take multiple arguments:
allkey = set().union(*alldict)
does what you want without any loops or lambdas.
Your solution works for the first two elements in the list, but then dict1 and dict2 got reduced into a set and that set is put into your lambda as the x. So now x does not have the method keys() anymore.
The solution is to make x be a set from the very beginning by initializing the reduction with an empty set (which happens to be the neutral element of the union).
Try it with an initializer:
allkey = reduce(lambda x, y: x.union(y.keys()), alldict, set())
An alternative without any lambdas would be:
allkey = reduce(set.union, map(set, map(dict.keys, alldict)))
A simple strategy for non-functional neurons (pun intended):
allkey = []
for dictio in alldict:
for key in dictio:
allkey.append(key)
allkey = set(allkey)
We can convert this code to a much sorter form using set comprehensions:
allkey = {key for dictio in alldict for key in dictio}
This one-liner is still very readable in comparison with the conventional for loop.
The key to convert a nested loop to a list or set comprehension is to write the inner loop (the one that varies faster in the nested loop) as the last index (that is, for key in dictio).
set().union(dict1.keys(),dict2.keys()...)
I tried the list and it didnt work so just putting it up here for anyone.
Just one more way, 'cause what the hay:
a={}; [ a.update(b) for b in alldict ] and a.keys()
or the slightly-more-mysterious
reduce(lambda a, b: a.update(b) or a, alldict, {}).keys()
(I'm bummed that there's no built-in function equivalent to
def f(a,b):
r = {}
r.update(a)
r.update(b)
return r
is there?)
If you only want to union keys of 2 dicts you could use operator |.
Quote from docs:
Return a new set with elements from the set and all others.
Example:
all_keys = (dict1.keys() | dict2.keys())

Categories

Resources