Understanding the syntax of list comprehensions - python

I don't understand the syntax for list comprehension:
newList = [expression(element) for element in oldList if condition]
The bit I don't understand is (element). Let's say you had a following code:
List = [character for character in 'Hello world!']
print(list)
And then you will get:
['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
Since the first character isn't quite an expression, what is it doing? Does it just mean that each item in the string is getting stored in a new list?

Python list comprehensions are for loops executed in a list to generate a new list.The reason python list comprehensions are evaluated backward from or right to left is because usually anything inside a bracket( [], {}, () ) in python is executed from right to left with just a few exeptions .Another thing to note is that a string is an iterable (lists,tuples, sets, dictionaries, numpy arrays) concatenating characters so it can be iterated over like a list.
List Comprhension form:
new_list = [item for item in my_list]
This will have the same effect:
for item in my_list:
my_list.append(item)
Since a strings is an iterable of characters you can do this:
my_list = [character for character in 'Hello world!']
print(list)
Output:
['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
Your list comprehension can also be written as:
my_list = []
for character in 'Hello world':
my_list.append(character)
print(my_list)
I am also pointing out that you shouldn't use built in methods(such as List) as variable names because when you do you overide them which will bar you from using that method in the future.
Here is a complete list of all builins as of python 3.9.6:

Let's understand the syntax for Python List Comprehensions using a few examples. Reference to complete documentation.
Basic usage: [<expression> for <item> in <iterable>]. In python, any object that implements the __next__() method is an iterable.
For example, List objects are iterables. Consider the following code:
list_a = [1, 2, 3]
list_b = [item for item in list_a] # [1, 2, 3]
list_c = [item + 1 for item in list_a] # [2, 3, 4]
list_d = [None for item in list_a] # [None, None, None]
Interestingly, a String object is also iterable. So when you iterate over a string, each item will be a character. This was the case in your example.
Now, coming to expressions. In python, any value (integer, float, char, etc) or any object is an expression. Just to clarify, the expression does not contain an equals symbol. This is an excellent answer to the question, "What is an expression in Python?".
I noticed that you had used (also pointed out in comments), list as the name of a variable. There are some keywords and names you should not use as variable names in Python. You can find the list of all such builtin names by: (refer this post for more details)
import builtins
dir(builtins)

Related

Appending list(element) to another list gives an element by letter [duplicate]

This question already has an answer here:
What is the difference between a list of a single iterable `list(x)` vs `[x]`?
(1 answer)
Closed 3 years ago.
Sorry for this question, but I do not understand why the difference between the following results when adding an element to the list as a list itself to other list:
list_a=[]
list_b=['HELLO','WORLD']
for word in list_b:
list_a.append([word])
print("Append to dist_list single word: ", list_a)
Output: Append to list_a: [['HELLO'], ['WORLD']]
list_a=[]
list_b=['HELLO','WORLD']
for word in list_b:
list_a.append(list(word))
print("Append to list_a: ", list_a)
output: Append to list_a: [['H', 'E', 'L', 'L', 'O'], ['W', 'O', 'R', 'L', 'D']]
When you perform list() to a string, the string gets turned into a list that's separated for each individual value. For example:
a = 'string'
b = list(a)
b = ['s','t','r','i','n','g']
Therefore the difference comes because in the first case you are appending two items (both being strings) and in the second one, you are appending the string previously turned into a list with the logic explained above, hence you've appended a list for each string. This is the differnece in the results you are getting. First case add two strings, second case add two lists.

In-place function to remove an item using index in Python [duplicate]

This question already has answers here:
A quick way to return list without a specific element in Python
(9 answers)
Closed 5 months ago.
Just noticed that there is no function in Python to remove an item in a list by index, to be used while chaining.
For instance, I am looking for something like this:
another_list = list_of_items.remove[item-index]
instead of
del list_of_items[item_index]
Since, remove(item_in_list) returns the list after removing the item_in_list; I wonder why a similar function for index is left out. It seems very obvious and trivial to have been included, feels there is a reason to skip it.
Any thoughts on why such a function is unavailable?
----- EDIT -------
list_of_items.pop(item_at_index) is not suitable as it doesn't return the list without the specific item to remove, hence can't be used to chain. (As per the Docs: L.pop([index]) -> item -- remove and return item at index)
Here's a nice Pythonic way to do it using list comprehensions and enumerate (note that enumerate is zero-indexed):
>>> y = [3,4,5,6]
>>> [x for i, x in enumerate(y) if i != 1] # remove the second element
[3, 5, 6]
The advantage of this approach is that you can do several things at once:
>>> # remove the first and second elements
>>> [x for i, x in enumerate(y) if i != 0 and i != 1]
[5, 6]
>>> # remove the first element and all instances of 6
>>> [x for i, x in enumerate(y) if i != 0 and x != 6]
[4, 5]
Use list.pop:
>>> a = [1,2,3,4]
>>> a.pop(2)
3
>>> a
[1, 2, 4]
According to the documentation:
s.pop([i])
same as x = s[i]; del s[i]; return x
UPDATE
For chaining, you can use following trick. (using temporary sequence that contains the original list):
>>> a = [1,2,3,4]
>>> [a.pop(2), a][1] # Remove the 3rd element of a and 'return' a
[1, 2, 4]
>>> a # Notice that a is changed
[1, 2, 4]
To get the result of removing (i.e, a new list, not in-place) a single item by index, there is no reason to use enumerate or a list comprehension or any other manual, explicit iteration.
Instead, simply slice the list before and after, and put those pieces together. Thus:
def skipping(a_list, index):
return a_list[:index] + a_list[index+1:]
Let's test it:
>>> test = list('example')
>>> skipping(test, 0)
['x', 'a', 'm', 'p', 'l', 'e']
>>> skipping(test, 4)
['e', 'x', 'a', 'm', 'l', 'e']
>>> skipping(test, 6)
['e', 'x', 'a', 'm', 'p', 'l']
>>> skipping(test, 7)
['e', 'x', 'a', 'm', 'p', 'l', 'e']
>>> test
['e', 'x', 'a', 'm', 'p', 'l', 'e']
Notice that it does not complain about an out-of-bounds index, because slicing doesn't in general; this must be detected explicitly if you want an exception to be raised. If we want negative indices to work per Python's usual indexing rules, we also have to handle them specially, or at least -1 (it is left as an exercise to understand why).
Fixing those issues:
def skipping(a_list, index):
count = len(a_list)
if index < 0:
index += count
if not 0 <= index < count:
raise ValueError
return a_list[:index] + a_list[index+1:]
As Martijn Pieters noted in comments to the question, this is not implemented as: Python in-place operations, as a rule, return None, never the altered object.

One word string made into a list of the letters

I have a list of words but I need to take the last item off the list, perform a function with the rest of the list then replace the last item. But for some reason when i go to to replace the last item, it does this...
>>> List = ['this', 'is', 'a', 'list']
>>> last = List[-1]
>>> others = List[:-1]
>>> others += last
>>> print others
['this', 'is', 'a', 'l', 'i', 's', 't']
Is there any way I can concatenate the list called last onto others but have it just one single element.
Try using append
others.append(last)
You can further simplify the code by doing this:
last = List.pop()
This removes the last element or List if no parameter is specified, and saves it in the variable last for you
Use append instead of +=:
>>> others.append(last)
Use:
others.append(last)
instead of
others += last
This is because:
When you are doing
list += ["somethingHere"]
it's equivalent to
list.extend(["somethingHere"])
According to the doc,
list.extend(L) = Extend the list by appending all the items in the given list
but
list.append(x) = Add an item to the end of the list
And what you need here is to " add an item " not to " append all the items in the given list " (all characters in this case.)
Please use one following:
others += [last]
others.append(last)
+ for list instances is iterating over element being added to it, thus iterating over string you get list of characters.
others += 'string'
others += ['s', 't', 'r', 'i', 'n', 'g']

Multiline list comprehension in python

How I make multiline list comprehension in Python?
Something like:
[
x for x in a:
if check(x):
....
#something multiline here
....
else:
....
#something multiline here
....
]
Of course I know that I can to something like:
def f(x):
if check(x):
....
else:
....
return x
map(a,f)
But I want it without additional functions.
Is it possible?
My understanding is that you can not do it as you suggested.
It's far more readable when you name the function and use list comprehension or map function compared to what you have suggested
You can't, in the way you're thinking; list comprehensions can only contain expressions, not statements.
You can have multiline list comprehensions and you can have if statements inside them, but the syntax is different from what you showed. I just tested this in the interpreter:
>>> tuple = ('a','b','c','d','e','f','g','h','i','j')
>>> list = [letter for letter in tuple
... if (letter != 'a' and letter != 'b')]
>>> list
['c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
You could also break it in other way, but the code will be a bit more messy:
>>> list = [letter for letter in
... tuple if (letter != 'j' and letter != 'i')]
>>> list
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
As the other guys pointed out, you might not use an else statement (couldn't make it work here). Besides, if the list comprehension start to grow too much it lose its conciseness (which I think it's strongest point).
Of course you can do multiple nested list comprehensions. I do it all the time. Here is one example:
A=[[[10 for y in range(3)],2][x<=3] for x in range(7)]
print A
It generates a list with 4 times 2 and three sublists with 3 times 10 as elements.
[2, 2, 2, 2, [10, 10, 10], [10, 10, 10], [10, 10, 10]]
As you can see, the outer list comprehension generates the 6 elements of the outer list, and the inner (first) list comprehension generates the inner 10s or the 2s, depending on whether x is smaller or equal to 3.

Python: Adding a word from a stringlist to another stringlist

I'm trying to add whole words from one string to another if they contain a certain character:
mylist = ["hahah", "hen","cool", "breaker", "when"]
newlist = []
for word in mylist:
store = word #stores current string
if 'h' in word: #splits string into characters and searches for 'h'
newlist += store #adds whole string to list
print newlist
the result I expect is:
newlist = ["hahah","hen","when"]
but instead I'm getting:
newlist = ['h', 'a', 'h', 'a', 'h', 'h', 'e', 'n', 'w', 'h', 'e', 'n']
How do I get my expected result?
Use append [docs]:
newlist.append(store)
Or shorter (using list comprehension [docs]):
newlist = [word for word in mylist if 'h' in word]
Why does newlist += store not work?
This is the same as newlist = newlist + store and is extending the existing list (on left side) by all the items in the sequence [docs] on the right side. If you follow the documentation, you will find this:
s + t the concatenation of s and t
In Python, not only lists are sequences, but strings are too (a sequence of characters). That means every item of the sequence (→ every character) is appended to the list.
Out of interest I decided to see which of the three solutions (the loop, the list comprehension and the filter() function) was the quickest. My test code and the results are below for anybody else who is interested.
Initialisation
>>> import timeit
>>> num_runs = 100000
>>> setup_statement = 'mylist = ["hahah", "hen","cool", "breaker", "when"]'
Loop
>>> loop_statement = """
newlist = []
for word in mylist:
if 'h' in word:
newlist.append(word)"""
>>> timeit.timeit(loop_statement, setup_statement, number=num_runs) / num_runs
4.3187308311462406e-06
List comprehension
>>> list_statement = "newlist = [word for word in mylist if 'h' in word]"
>>> timeit.timeit(list_statement, setup_statement, number=num_runs) / num_runs
2.9228806495666502e-06
Filter call
>>> filter_statement = """
filt = lambda x: "h" in x
newlist = filter(filt, mylist)"""
>>> timeit.timeit(filter_statement, setup_statement, number=num_runs) / num_runs
7.2317290306091313e-06
Results
List comprehension at 2.92us
Loop at 4.32us (48% slower than the list comprehension)
Filter call at 7.23us (148% slower than the list comprehension)
Another alternate syntax for expressing this is to use filter. Thus, an implementation for your problem would look something like
filt = lambda x: 'h' in x
newlist1 = filter(filt, mylist)
try to use:
newlist.append(store)

Categories