can this be done in one line in python? - python

I feel this can be done in one line, but I cannot find a way to do.
# final_list is what I want as an output
final_list = []
for x in some_list:
# y is a dictionary
y = x.get_some_dict()
# Want to add a new key/value pair to y, which comes from x
y.update({"new_key": x.property_in_x})
# append y to the output list
final_list.append(y)
return final_list

I wouldn't recommend collapsing this into a one line list comprehension. It can be done, but it's bad style. List comprehensions shouldn't have side effects (i.e. calling update).
You could get replace the explicit list appending with a generator. That wouldn't be a bad idea. And d[k] = v is simpler than d.update({k: v}).
def final_list(some_list):
for x in some_list:
y = x.get_some_dict()
y["new_key"] = x.property_in_x
yield y

I wouldn't recommend damping it into a one liner, which will (probably) be messy and unreadable. Also, the update makes a problem with the one liner solution.
But, In my opinion, this can be simplified, to be clearer:
(Shortened, but not to an unreadable one liner)
for x in some_list:
x.get_some_dict().update({"new_key": x.property_in_x})
final_list = [y.get_some_dict() for y in some_list]

Below is the equivalent list comprehension expression along with for loop as:
final_list = [x.get_some_dict() for x in some_list]
for dict_item, base_item in zip(final_list, some_list):
dict_item["new_key"] = base_item.property_in_x

Related

How to access values from nested list using for loop

I have one of problem statement
List =[[[1,2],[3,4]]]
And i want 1st index from both nested list in list a and 2nd index from both nested list in list b using for loop and if else not using append()
Like:
a = [1,3]
b = [2,4]
How about this:
l = [[[1,2],[3,4]]]
a = []
b = []
for x in l[0]:
a.append(x[0])
b.append(x[1])
There is more pythonic way to do this, but code above is written to make it understandable.
If you write
a=[List[0][0][0], List[0][1][0]]
b=[List[0][0][1], List[0][1][1]]
You get what you want. You can define it in a loop, of course
l = [[[1,2],[3,4]]]
a = [x[0] for x in l[0]]
b = [x[1] for x in l[0]]
List comprehensions are essentially for loops in lists they pretty much read like a sentence:
do x FOR x in OTHER_LIST (and wrap that in a list)

Having problems with if and else in list comprehensions. I need to make the list value something if the list is empty

I have this:
name_list = [x for x in list]
if not name_list:
name_list = "n/a"
I want to make it in one line.
I want this:
name_list = ["n/a" if not x else x.text for x in list]
The problem I'm having if that I don't know what to put in the first x of the above code.
How do I check if the list is empty and make the value "n/a" in one line?
In the first code snippet, if the list is empty you assign a string to it. Not a list. Hence you can't do it with list comprehension, as the latter always returns a list.
You can use other Python builtin feature to achieve that:
name_list = [x.text for x in list] or "n\a"
It will evaluate the first expression first, and if its Falsey (None, False, 0) it will use the other expression - n\a.
You're mistaken here. You don't want a list comprehension. You use list comprehensions when you need to build new lists. That's not what you want to do here. You want to assign a certain value to name_list depending on a condition.
This can be done using Python's or operator. The or operator is short-circuited, and returns the first 'truthy' value it evaluates:
name_list = [x for x in list] or "n\a"
However, I would recommended being careful using the above code, as it can be confusing for people who aren't familiar with it. Depending on your case, it might be better to be more explicit and break the above code into two steps:
tmp = [x for x in list]
name_list = tmp if tmp else "n\a"
You can simply use or to do that like:
name_list = [x for x in a_list] or "n/a"
or is a short-circuit operator, so it only evaluates the second argument if the first one is false.

How to loop though range and randomly shuffle a list in Python?

Given a list x = [1,0,0,1,1]I can use random.shuffle(x) repeatedly to shuffle this list, but if I try to do this a for loop the list doesn't shuffle.
For example:
x = [1,0,0,1,1]
k = []
for i in range(10):
random.shuffle(x)
k.append(x)
return x
Basically, kcontains the same sequence of x unshuffled? Any work around?
One pythonic way to create new random-orderings of a list is not to shuffle in place at all. Here is one implementation:
[random.sample(x, len(x)) for _ in range(10)]
Explanation
random.sample creates a new list, rather than shuffling in place.
len(x) is the size of the sample. In this case, we wish to output lists of the same length as the original list.
List comprehensions are often considered pythonic versus explicit for loops.
As mentioned by #jonrsharpe, random.shuffle acts on the list in place. When you append x, you are appending the reference to that specific object. As such, at the end of the loop, k contains ten pointers to the same object!
To correct this, simply create a new copy of the list each iteration, as follows. This is done by calling list() when appending.
import random
x = [1,0,0,1,1]
k = []
for i in range(10):
random.shuffle(x)
k.append(list(x))
Try this:
x = [1,0,0,1,1]
k = []
for i in range(10):
random.shuffle(x)
k.append(x.copy())
return x
By replacing x with x.copy() you append to k a new list that looks like x at that moment instead of x itself.

Python: What's the "Pythonic" way to process two lists?

Say I have this code in Python. I'm a Perl programmer, as you may be able to tell.
# Both list1 and list2 are a list of strings
for x in list1:
for y in list2:
if y in x:
return True
return False
What's a more Pythonic way to handle this? I assume a list comprehension could do it well, but I can't get my head around the "process two separate lists" part of this.
To convert two nested loops into a nested comprehension, you just do this:
[<expression> for x in list1 for y in list2]
If you've never thought through how list comprehensions work, the tutorial explains it:
A list comprehension consists of brackets containing an expression followed by a for clause, then zero or more for or if clauses. The result will be a new list resulting from evaluating the expression in the context of the for and if clauses which follow it.
In other words, the clauses from left to right in a comprehension match up with statements from top/outside to bottom/inside, and that's all there is to it.
This blog post attempts to put the same idea in yet another way, in case you haven't got it yet.
But here, you don't have an expression, you have a statement.
But you have an expression in there, the y in x part of the statement, and what you want to do is return True if it's every true for any value, which is exactly what any does. So:
return any([y in x for x in list1 for y in list2])
And really, you don't want to build the list here, just iterate over the values, so drop the square brackets to make it a generator expression instead:
return any(y in x for x in list1 for y in list2)
For the simple case of just iterating the cartesian products of multiple iterables, you may want to use itertools.product instead. In this case, I don't think it makes things any simpler or more readable, but if you had four lists instead of two—or an unpredictable-in-advance number of them—that might be a different story:
return any(y in x for x, y in product(list1, list2))
No, a list comprehension can't do it well. You want a boolean result, list comprehensions are for creating lists (and they don't really do early exit). You could use a generator comprehension:
return any(y in x for x, y in itertools.product(list1, list2))
or if you really like using standard libraries for everything (or you think like a functional programmer):
from itertools import starmap, product
from operator import contains
return any(starmap(contains, product(list1, list2))
Steve and abamarts answers are explaining what you asked explicitly, i would try to address what you implied regarding list comprehensions.
A "nested" list comprehension is nothing more then your original nested for loop, but with the twist, that the most inner-block moves up to the top!
for x in list1:
for y in list2:
if y in x:
return True
else:
return False
becomes:
[True if y in x else False for x in list1 for y in list2]
So the for-loops remain more or less in order:
[for x in list1 for y in list2]
then prepend the if-clause:
[if y in x else False for x in list1 for y in list2]
and finally prepend the result for the if-statement to be True:
[True if y in x else False for x in list1 for y in list2]
a nested example:
tpl_list = []
for element in vector:
for x, y in element:
if (x**2+y**2) < 1:
tpl_list.append((1/x, 1/y))
else:
tpl_list.append((x,y))
as a list comprehension (building in steps)
[for e in vector for x,y in e]
[if (x**2+y**2) < 1 else for e in vector for x,y in e]
[(1/x, 1/y) if (x**2+y**2) < 1 else (x,y) for e in vector for x,y in e]

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'

Categories

Resources