I've seen this question before, but it only deals with recursions that are linear in nature. I'm looking for something more general.
Suppose I have the following code
n = 10
num_bits = [0]
for i in range(n):
nums_bits.append(num_bits[i>>1]+i%2)
This code will compute num_bits, a 11 element array of value with num_bits[i] representing the number of bits it takes to represent i.
Is it possible to write this as a list comprehension? Something like this doesn't work
num_bits = [0]*11
num_bits = [num_bits[i>>1]+i%2 for i in range(11)]
since the comprehension doesn't update the value of num_bits in the middle of evaluation. Is there a canonical way to do something like this, besides a for loop?
P.S. I'm aware there are other ways to solve this problem: I'm just using it as a vehicle to understand Python's features better.
Edit: To summarize, I'd like to know what the proper way of generating lists of values that are dependent on previous values is. For a simpler example, consider the Fibonacci Numbers
fibonacci = [0,1]
for i in range(10):
fibonacci.append(fibonacci[-1]+fibonacci[-2])
Is there a way to generate these numbers in a comprehension? If not, what tools are there for this other than for loops (or are for/while loops my only option)?
Given it is not a piece of code I'd recommend, for the reasons discussed in the comments above and in the other answer, this comprehension should be faster than the for loop:
fibonacci = [0,1]
deque((fibonacci.append(fibonacci[-1]+fibonacci[-2]) for _ in range(10)), maxlen=0)
as it fills the list consuming the generator and discarding the result (an empty queue, it's the fastest recommended way to consume an iterator)
It produces:
>>> fibonacci
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
No.
There is no nice way to do this with a list comprehension, and that is not what they’re for. The purpose of list comprehensions is to offer a more readable alternative to maps and filters, and this isn’t that, so it’s not possible to do this in a sensible way.
Related
Recently, I've found a code for developing a set of lists from a list, that code was written by user Mai, answering question but i have not understood it yet. Could somebody help me to understand it? And... is there a way to rewrite that code that be easier? The code is:
def even_divide(lst, num_piece=4):
return [
[lst[i] for i in range(len(lst)) if (i % num_piece) == r]
for r in range(num_piece)
]
Thanks!
It's pretty simple actually. Just follow through the values of the two loops:
Starting with the outer loop, r would be 0, then 1, then 2, etc. Let's look at the case for which r == 1. When running through the different values of i, (which would be 0, 1, 2, ... len(lst), the value of i % 4, meaning the remainder of dividing i by 4, would be 0, 1, 2, 3, 0, 1, 2, 3, .... So the i % 4 would be equal to r, for every 4 values of i!
For our chosen r == 1, that would mean we're choosing lst[1], lst[5], lst[9], ..., etc.
And for r == 2? You guessed it! You'd be picking up lst[2], lst[6], lst[10],....
So over all you'd get 4 lists, with non-overlapping elements of the original list, by just "jumping" 4 elements every time, but starting at different values.
Which naturally leads to the more simple solution:
def even_divide(lst, num_piece=4):
return [lst[r::num_piece] for r in range(num_piece)]
Could somebody help me to understand it?
Sure! It's a list comprehension. A list comprehension takes a list and does something to or with every element in that list. Let's say I want to multiply every element in my list by 2:
new_list = [element*2 for element in my_list]
What makes it a list comprehension is the bracket syntax. For those new to it, that's usually the part that takes a moment to get used to. With that said, I assume that is what is giving you difficulty in understanding the code in your question, as you have a list comprehension in a list comprehension. It might be difficult to understand now, but list comprehensions are a wonderful thing in python.
But, as this post mentions, there's a lot of discussions around list comprehension, lambda's, map, reduce, and filter. Ultimately, its up to you to decide what's best for your project. I'm not a fan of anything else but list comprehensions, so I use those religiously.
Based on the question you've linked, the list comprehension takes a 1d list of length x and turns it into a 2d list of (length x, width y). It's like numpy.reshape.
And... is there a way to rewrite that code [to] be easier?
I would not recommend it. List comprehensions are considered very pythonic and you will see them everywhere. Best to use them and get used to them.
I want to find the lowest integer in a list, which contains strings and integers. Is there a quick way to find it?
I could solve the issue with regex. But that sounds too much work for this.
Create a new list, with list comprehension sounds better. But isn't there an easier way?
my_list = [2, 4, 'foo']
of course min(my_list) won't work because of the string inside.
You can use a generator expression to filter out non-ints:
min(n for n in my_list if isinstance(n, int))
# returns 2
A=[2,3,5,7,11,13]
print(A.index(5))
The answer is 2,
But what I need is the first one which is bigger than 4 (the answer will be the same - 2).
I can apply a while loop, but is there a more elegant or a builtin way to do it?
In my problem the list is sorted in an ascending order (no duplication),
and my target is to split it into two lists: lower or equal to 4, and bigger than 4; and given the list is sorted it would be redundant to scan it twice (or even once).
As #DanD.mentioned, you can use the bisect module for this, in you example you can use bisect_left
>>> import bisect
>>> bisect.bisect_left(A, 5)
2
This will use a binary search since your data is sorted, which will be faster than a linear search (O(logN) instead of O(N)).
If you want the index of the first value greater than 4, then you can switch to bisect_right
>>> bisect.bisect_right(A, 4)
2
You're totally correct about efficiency - if you have already sorted list, do not iterate linearly, its waste of time
There's built-in bisect module - exactly for binary search in sorted containers.
You're probably looking for bisect_right function.
Thanks everybody, the answer using your kind help is:
import bisect
A=[2,3,5,7,11,13]
N=bisect.bisect_right(A,4)
print(A[:N]) #[2,3]
print(A[N:]) #[5,7,11,13]
Use next with a default argument:
val = next((i for i, x in enumerate(A) if x > 4), len(A))
Given the above result, you can then do:
left, right = A[:val], A[val:]
To find the maximal value in a matrix of numbers, we can code 5 lines to solve the problem:
ans = matrix[0][0]
for x in range(len(matrix)):
for y in range(len(matrix[0])):
ans = max(ans, matrix[x][y])
return ans
Is there a one line solution for this problem?
The one that I came up with is pretty awkward actually:
return max(max(matrix, key=max))
or
return max(map(max, matrix))
You can use generator expression to find the maximum in your matrix. That way you can avoid building the full list of matrix elements in memory.
maximum = max(max(row) for row in matrix)
instead of list comprehension as given in a previous answer here
maximum = max([max(row) for row in matrix])
This is from PEP (the rationale section):
...many of the use cases do not need to have a full list created in
memory. Instead, they only need to iterate over the elements one at a
time.
...
Generator expressions are especially useful with functions like sum(), min(), and max() that reduce an iterable input to a single value
...
The utility of generator expressions is greatly enhanced when combined with reduction functions like sum(), min(), and max().
Also, take a look at this SO post: Generator Expressions vs. List Comprehension.
By matrix, I assume you mean a 2d-list.
max([max(i) for i in matrix])
using numpy.amax:
import numpy as np
>>> my_array
array([[1, 2, 3],
[9, 8, 6]])
>>> np.amax(my_array)
9
You can also flatten your array:
from itertools import chain
flatten = chain.from_iterable
max(flatten(matrix))
This should be trivial. Yet I don't feel 100% sure about my trick.
I have a list of lists (lol ;)) that captures edge relationships between nodes of a graph. Let's say I have a directed graph with 4 nodes labeled 0, 1, 2, 3. The edges are {(0,2),(0,3),(1,0),(1,3),(2,1)} and so the adjacency lol (call it a) is
a = [[2,3],[0,3],[1],[]]
I want to find the incidence lol now, i.e. a list of lists which indicate which nodes are incident on which nodes. For this example, the incidence lol (call it b) would be:
[[1], [2], [0], [0, 1]]
I tried the following code:
b = [[],[],[],[]]
[b[j].append(i) for i,x in enumerate(a) for j in x]
This gives me the right incidence matrix b.
The second step, although works, should ideally be b[j].append(i) for i,x in enumerate(a) for j in x, without the opening [ and closing ]. But Python interpreter cries syntax error without it. Is there a better way of phrasing it?
Your question is essentially about using list comprehensions for side effects. As, e.g. the answers to this question say, breaking it down into a for loop (or loops) is the way to go:
for i, x in enumerate(a):
for j in x:
b[j].append(i)
Also, please note that list comprehensions are used to construct lists in a very natural, easy way, like a mathematician is used to do. That is why, in Python, syntax requires square brackets (in your case).