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.
Related
Why this problem has no trivial solution is because I needs to be solved using only pure functions.
Using only pure functions from Python's functional programming page (https://docs.python.org/3/howto/functional.html#), how can one create a list with a value in it? If we'd like to create a list with a value in it, we'd (in code) just do
x = [1]
I do not consider [] to be to be a part of the functions we're looking at here, since it has no signature and is not callable like any other function.
Using only functions to do this is not so trivial. One thought I had was to create a new list using list() and then append values to it. But list().append is mutable and does not return a new, or the, list with the item in it.
What I really want to do is to turn ["a","b","c"] into [["a"],["b"],["c"]], with above constraints.
Other proposals has been made like creating my own (pure) function doing what I want:
def create_list(value) -> list:
return [value]
and then just do map(create_list, ["a","b","c"]) to get solution.
But this is a custom made function and is not from any of the python package functions (within https://docs.python.org/3/howto/functional.html, as mentioned)
lst=[1,2,3];
#this will print [[1],[2],[3]]
print(list(map(lambda x: [x],lst)));
Single element:
def to_list(elem):
return list(range(elem, elem+1)))
To convert [1,2,3] into [[1], [2], [3]] with list comprehesion (it can be easily changed to map):
return [to_list(el) for el in input_list]
And without (ugly, but works ^^)
import itertools
def make_gen(elem):
yield elem
def to_list(elem):
return list(make_gen(elem))
def helper(elem, l):
return list(itertools.chain(to_list(to_list(elem)), l))
def convert(l):
if not l:
return []
return helper(l[0], convert(l[1:]))
print(convert([1, 2, 3]))
To ensure non-mutability, you probably want to use tuples instead of lists (or be very disciplined with your lists).
Using a list comprehension would be a valid functional approach:
A = [1,2,3]
B = [ [i] for i in A ] # [[1], [2], [3]]
or with tuples:
A = (1,2,3)
B = tuple( (i,) for i in A ) # ((1,), (2,), (3,))
If you must use functions, then map() is probably a good solution to this:
A = [1,2,3]
B = list(map(lambda i:[i],A))
If even [i] is proscribed (but why would it be), you can use a a function to make a list directly from its arguments:
def makeList(*v): return list(*v)
A = makeList(1,2,3)
B = makeList(*map(makeList,A))
# combined
makeList(*map(makeList,makeList(1,2,3)))
BTW functional programming is not about "only using functions", it is more about non-mutability of results (and avoidance of side effects). You may want to question whoever is sending you on this wild goose chase.
Using only pure functions from Python's functional programming page
(https://docs.python.org/3/howto/functional.html#), how can one create
a list with a value in it? If we'd like to create a list with number 1
in it
You might exploit generator as generator are described therein as follows
def justone():
yield 1
lst = list(justone())
print(lst)
output
[1]
justone is function (which might be checked using inspect.isfunction) and is pure (as it does not alter anything outside)
In the documentation you link, there are references to Iterators and Generators, which are powerful constructs present in Python (and other languages). You can consider a function to build a list as follows:
def list_from_args(*args):
return [*args]
This is a (superfluous) wrapper around Iterator functionality. You can leverage the Iterator pattern in Python to accomplish a lot, whether that be creating/consuming objects (e.g. lists, tuples, dictionaries), or for processing data (e.g. reading/writing to a file line-by-line, paginating an API or DB Query, etc.)
The code above does the following, for example:
>>> example = list_from_args(1, 'a', 'ham', 'eggs', 44)
>>> example
[1, 'a', 'ham', 'eggs', 44]
The reason I labeled the above function as superfluous: Oftentimes, if you need to create a list on the fly, you can use list comprehensions.
This does it using only functions from https://docs.python.org/3/library/functional.html
import functools
import itertools
map(
list,
map(
functools.partial(
itertools.repeat,
times=1,
),
[1,2,3]
)
)
functools.partial creates a new function of itertools.repeat with "times" parameter set to 1. Each value in the list is then repeated once and turned into a new list using list function.
>>> [[1], [2], [3]]
I have a list of dicts like so:
a = [ {'list':[1,2,3]}, {'list':[1,4,5]} ]
Am trying to get a flat set of the values in the list key like {1,2,3,4,5}. What's the quickest way?
You can write a loop like:
result = set()
for row in a:
result.update(row['list'])
which I think will work reasonably fast.
Or you can simply use set comprehension and that will result in the following one-liner:
result = {x for row in a for x in row['list']}
In case not all elements contain a 'list' key, you can use .get(..) with an empty tuple (this will reduce construction time):
result = {x for row in a for x in row.get('list',())}
It is not clear what your definition of "quickest" is, but whether it is speed or number of lines I would use a combination of itertools and a generator.
>>> import itertools
>>> a = [ {'list':[1,2,3]}, {'list':[1,4,5]} ]
>>> b = set(itertools.chain.from_iterable(x['list'] for x in a if 'list' in x))
Note that I have added a guard against any elements that may not contain a 'list' key; you can omit that if you know this will always be true.
flat list can be made through reduce easily.
All you need to use initializer - third argument in the reduce function.
reduce(
lambda _set, _dict, key='list': _set.update(
_dict.get(key) or set()) or _set,
a,
set())
Above code works for both python2 and python3, but you need to import reduce module as from functools import reduce. Refer below link for details.
for python2
for python3
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))
I want to check if a value is in a list, no matter what the case of the letters are, and I need to do it efficiently.
This is what I have:
if val in list:
But I want it to ignore case
check = "asdf"
checkLower = check.lower()
print any(checkLower == val.lower() for val in ["qwert", "AsDf"])
# prints true
Using the any() function. This method is nice because you aren't recreating the list to have lowercase, it is iterating over the list, so once it finds a true value, it stops iterating and returns.
Demo : http://codepad.org/dH5DSGLP
If you know that your values are all of type str or unicode, you can try this:
if val in map(str.lower, list):
...Or:
if val in map(unicode.lower, list):
If you really have just a list of the values, the best you can do is something like
if val.lower() in [x.lower() for x in list]: ...
but it would probably be better to maintain, say, a set or dict whose keys are lowercase versions of the values in the list; that way you won't need to keep iterating over (potentially) the whole list.
Incidentally, using list as a variable name is poor style, because list is also the name of one of Python's built-in types. You're liable to find yourself trying to call the list builtin function (which turns things into lists) and getting confused because your list variable isn't callable. Or, conversely, trying to use your list variable somewhere where it happens to be out of scope and getting confused because you can't index into the list builtin.
You can lower the values and check them:
>>> val
'CaSe'
>>> l
['caSe', 'bar']
>>> val in l
False
>>> val.lower() in (i.lower() for i in l)
True
items = ['asdf', 'Asdf', 'asdF', 'asjdflk', 'asjdklflf']
itemset = set(i.lower() for i in items)
val = 'ASDF'
if val.lower() in itemset: # O(1)
print('wherever you go, there you are')
I'm seeking advice on doing the following in a more pythonic way.
Consider:
class MyObj(object):
def __init__(self):
self.dict_properties = {}
Suppose I've got a list which contains multiple MyObj instances:
mylist = [<__main__.MyObj object at 0x1005e3b90, ...]
Now i want to sort mylist based on the value of a certain key in dict_properties in MyObj.
What does work is:
mylist.sort(lambda x,y: cmp(x.dict_properties['mykey'],
y.dict_properties['mykey']))
but that hardly feels pythonic.
Is there a better way (perhaps using operator.attrgetter)?
mylist.sort(key=lambda x: x.dict_properties['mykey'])
is way simpler, and faster. You could reach for operator and try to compose an attrgetter and an itemgetter, but a straightforward lambda (or def) seems simplest here.
I'd just do:
mylist.sort(key=lambda o: o.dict_properties["kykey"])
You could also overide cmp on the class.
If speed is an issue, then use decorate-sort-undecorate:
mylist_decorated = [(elem.dict_properties['mykey'], elem) for elem in mylist]
mylist_decorated.sort()
mylist = [elem[1] for elem in mylist_decorated] # or zip(*mylist_decorated)[1] :)
this way sort() can spread its wings.