Python List Comprehensions - python

I am learning python3 list comprehensions. I understand how to format a list comprehension: [equation, for loop, if statement for filtering], but I cannot figure out how to condense three lines of code into a single equation for the 'equation' part.
I am taking a number and adding it to itself and then taking the result and adding it to itself and so on to create a sequence of numbers in the list.
I can accomplish this by declaring x = 1 and then looping the following:
y = x + x
x = y
Can anybody help me to turn this into a single-lined equation and if possible, resources that I might study to help me with this in the future?

Your algorithm is equivalent to multiplying by powers of 2:
x = 3
res = [x * 2**i for i in range(10)]
# [3, 6, 12, 24, 48, 96, 192, 384, 768, 1536]
To see why this is the case, note you are multiplying your starting number by 2 in each iteration of your for loop:
x = 3
res = [x]
for _ in range(9):
y = x + x
x = y
res.append(y)
print(res)
# [3, 6, 12, 24, 48, 96, 192, 384, 768, 1536]
As #timgeb mentions, you can't refer to elements of your list comprehension as you go along, as they are not available until the comprehension is complete.

Related

How to make list of lists, where you take the square and cube of each even number?

I would like to make a list of lists after squaring and cubing each even number.
Below is my code i have thus far:
def sq_cube(numbers):
ls1 = []
for i in numbers:
if i%2 == 0:
ls1.append(i)
else:
pass
ls2square = [x**2 for x in ls1]
ls3cube = [x**3 for x in ls1]
ls4all = list(ls2square +ls3cube)
return ls4all
RUN: sq_cube([1,2,3,4,6])
OUTPUT:[4, 16, 36, 8, 64, 216]
I would love my OUTPUT to be: [[4, 8], [16, 64], [36, 216]]
ls1: Here I sorted the list 1,2,3,4,6 into even numbers.
ls2square: Squared the even number in ls1.
ls3cube: Cubed the even numbers in ls1.
As you can see in my OUTPUT it gives both lists but it does not give each even
number its separate list where that even number was squared and cubed.
The problem comes from ls4all. You code is
ls4all = list(ls2square +ls3cube)
variable ls4all does not contain the desired list of lists: [[4, 8], [16, 64], [36, 216]] since it's the concatenation of ls2square and ls3cube. We would rather like to have the list of pairs of elements in ls2square and ls3cube. To achieve that, you can create an iterator that outputs the pairs of elements of ls2square and ls3cube, for instance, using zip command.
zip command works like that:
>>> list(zip([1,10], [2,20]))
[(1, 2), (10, 20)]
As you can see, it gathers together elements in [1,10] and [2,20], making pairs.
So you can use zip this way:
ls2square = [4, 16, 36]
ls3cube = [8, 64, 216]
ls4all = list([a,b] for a,b in zip(ls2square, ls3cube))
print(ls4all)
anyway, a shorter answer would be:
>>> print([(k**2, k**3) for k in [1,2,3,4,6] if k % 2 == 0])
[(4, 8), (16, 64), (36, 216)]
UPDATE:
In case your integers have type float, k % 2 will raise the following error
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: float modulo
So, if you want to round your float to the closest integer, just use round function like so:
ls2square = [round(x)**2 for x in ls1]
ls3cube = [round(x)**3 for x in ls1]
Short answer above is now:
>>> print([(round(k)**2, round(k)**3) for k in [1.0, 2.0, 3.0, 4.0, 6.0] if round(k) % 2 == 0])
[(4, 8), (16, 64), (36, 216)]
since you want the squares and the cubes of the same number to be in the same list you could use this, since both lists(ls2square,ls3cube) have the same length instead of just adding them together you can add in seperate list the each corisponding elements that they have, element 0 in ls2square goes with element 0 of ls3cube and so on:
def sq_cube(numbers):
ls1 = []
for i in numbers:
if i%2 == 0:
ls1.append(i)
else:
pass
ls2square = [x**2 for x in ls1]
ls3cube = [x**3 for x in ls1]
ls4all= [[ls2square[k],ls3cube[k]] for k in range(len(ls3cube))]
return ls4all
Create a new list
Round incoming list
loop for every number to check if even
then square and cube that number
def sq_cube(numbers):
new_string = []
numbers = [round(num) for num in numbers]
for W in numbers:
if W % 2 ==0:
new_string.append([W**2,W**3])
return new_string

Using "for" loop structure, generating numbers and filtering them by "length" and "% (mod)" structure

(Coding source)
import numpy as np
arr = np.array([2,4,9,10])
psuedo = [arr + 11 * x for x in range(1, 10)] # generate numbers using "arr" values
for i in range(len(arr)): # call each values in "arr"
if psuedo % arr[i] == 0: # each values in "arr" applies and divides to generated numbers
break # if generated numbers are divided by each "arr" values then break
else:
print(psuedo) # else, then print.
Results:
[array([13, 15, 20, 21]), array([24, 26, 31, 32]), array([35, 37, 42, 43]), array([46, 48, 53, 54])]
Expected results:
[array([13, 15, 21])], array([31]), array([35, 37, 43]), array([53])
I expected that the generated each number (results) would be divided by each of 2, 4, 9, and 10, and printed out as long it satisfied pseudo % arr[i] !=0.
What is the problem above coding?
The problem with your code is that the operation pseudo % arr[i] returns a new array of arrays with each array being replaced with the results of modding each element of that array with arr[i]. So then comparing this array of arrays to 0 doesn't make sense. What you probably want to do is iterate through all of the arrays of pseudo, and then filter out the elements from those individual arrays which don't satisfy your condition, like this:
import numpy as np
arr = np.array([2,4,9,10])
pseudo = [arr + 11 * x for x in range(1, 10)]
def is_not_mod(x):
keep = True
for mod in arr:
if x % mod == 0:
keep = False
break
return keep
for idx, array in enumerate(pseudo):
pseudo[idx] = np.array(list(filter(is_not_mod, array)))
print(pseudo)
Honestly I have almost no idea what you try to calculate. But there are some things that might fundamentally not work the way you intend.
First of all pseudo % arr[i] == 0 is wrong on multiple levels, I have no idea which Python version you are using that this does not create errors.
break stops the for-loop. My guess is that you want to use continue (go to next iteration) or pass (do nothing) instead (and thus you could simplyfiy the code omitting it completely)
This is my guess:
import numpy as np
arr = np.array([2, 4, 9, 10])
pseudo = [arr + 11 * x for x in range(1, 10)]
print([[i for i in x if (i%arr).all()] for x in pseudo])
This creates
[[13, 15, 21], [31], [35, 37, 43], [53], [57, 59, 65], [75], [79, 87], [97], [101, 103, 109]]
Let me explain:
Looping over arrays x inside pseudo and the values i in x, so the first x would be np.array([13, 15, 20, 21]) and the first i inthere would be 13.
(i%arr) is an array np.array([i%2, i%4, i%9, i%10])
.all() returns True if all values are non-zero, i.e. if your i is not divisible by any of the elements in arr.
[i for i in x if (i%arr).all()] is a list comprehension, so we create a new list with all elements in x that are not divisible by any of the elements in arr.
My output contains lists, but you can simply create np.arrays if that's better

Trying to form a list that takes its size from the number of elements in another list and appends the elements of the first list to the new list

for n in range(1,(len(randnum))/3):
X.append(randnum(n))
for i in range((len(randnum))/3 , (2/3)*len(randnum)):
Y.append(randnum(i))
for r in range ((2/3)*len(randnum) , len(randnum)):
Z.append(randnum(r))
I have been trying to form a list based on this criteria and I keep getting this error message for specifically this line below:
for n in range(1,(len(randnum))/3):
TypeError: 'float' object cannot be interpreted as an integer
The part of the program that is causing the problems is that part above and if I can fix it I can take the error and apply it to the rest.
Here is an example list that is used to fill the other three it has 20 elements and I want each list that I form to take from this list about 1/3 of its elements from different positions:
[ 59.18013391 12159.7881626 26308.21887981 8357.05103068
20718.85232457 16333.1546026 9828.75690047 10273.65018539
5949.58907673 8767.68292925 31826.29595355 13749.12915211
25423.61181129 28799.50849876 9517.54482827 27275.19296144
12460.2541769 25883.7888204 10393.9452616 26008.572598 ]
And I want this code to form 3 new lists containing in for example
X = [59.18013391 12159.7881626 26308.21887981 8357.05103068
20718.85232457 16333.1546026]
Y = [9828.75690047 10273.65018539
5949.58907673 8767.68292925 31826.29595355 13749.12915211 ]
Z = [ 25423.61181129 28799.50849876 9517.54482827 27275.19296144
12460.2541769 25883.7888204 10393.9452616 26008.572598]
You cannot use float for the range() function.
See: https://docs.python.org/3/library/stdtypes.html#range
(len(randnum))/3
that's float!
possible fix :
int((len(randnum))/3)
OKAY, perhaps your should try random
With repetition
import random
original_list =[ i for i in range(20)]
X = random.sample(original_list, int(len(original_list)/3))
Y = random.sample(original_list, int(len(original_list)/3))
Z = random.sample(original_list, int(len(original_list)/3))
Sample Output
X: [7, 3, 18, 15, 19, 1]
Y : [6, 13, 17, 4, 14, 5]
Z: [19, 2, 8, 18, 13, 17]
Without repetition
from random import shuffle
shuffle(original_list)
list(zip(*[iter(original_list)]*int(len(original_list)/3)))
Sample Output
[(17, 13, 15, 5, 16, 12), (14, 4, 18, 2, 19, 6), (10, 11, 7, 3, 1, 0)]
If I follow your goal, a simple approach would be to shuffle a copy of the list and then take every 3rd element starting at 0, then 1, then 2:
tmp_data = data.copy()
random.shuffle(tmp_data)
new_lists = [tmp_data[i::3] for i in range(3)]
which gives me, e.g.
In [361]: new_lists
Out[361]:
[[13749.12915211,
26008.572598,
25423.61181129,
8767.68292925,
12460.2541769,
26308.21887981,
59.18013391],
[9828.75690047,
20718.85232457,
10273.65018539,
9517.54482827,
27275.19296144,
8357.05103068,
5949.58907673],
[28799.50849876,
12159.7881626,
25883.7888204,
16333.1546026,
10393.9452616,
31826.29595355]]
and you could then do
X, Y, Z = new_lists
if you insisted on separate named variables.
(You could also simply do tmp_data = random.sample(data, len(data)) to get a random permutation of the list instead, but for some reason I find this less clear than shuffling. Not sure why.)
You could use random here but also you are going to need to make sure you don't use that random int again, my approach is append it to a used list and check that list to see if it can be used again, as far as splitting them you have 20 so you can use // floor division and % to help you create two lists of 7 items and one of 6 items.
import random
data = [
59.18013391,12159.7881626,26308.21887981, 8357.05103068,
20718.85232457,16333.1546026,9828.75690047, 10273.65018539,
5949.58907673, 8767.68292925, 31826.29595355, 13749.12915211,
25423.61181129, 28799.50849876, 9517.54482827, 27275.19296144,
12460.2541769, 25883.7888204, 10393.9452616, 26008.572598
]
y = len(data)//3
z = int((len(data) % 3)/2)
used = []
l1 = []
l2 = []
l3 = []
for i in range(y):
x = random.randint(0, len(data)-1)
while x in used:
x = random.randint(0, len(data)-1)
used.append(x)
l1.append(data[x])
for i in range(y+z):
x = random.randint(0, len(data)-1)
while x in used:
x = random.randint(0, len(data)-1)
used.append(x)
l2.append(data[x])
for i in range(y+z):
x = random.randint(0, len(data)-1)
while x in used:
x = random.randint(0, len(data)-1)
used.append(x)
l3.append(data[x])
chrx#chrx:~/python/stackoverflow/9.23$ python3.7 loop.py
l1: [8357.05103068, 10273.65018539, 26008.572598, 5949.58907673, 28799.50849876, 8767.68292925]
l2: [25423.61181129, 13749.12915211, 26308.21887981, 9828.75690047, 59.18013391, 16333.1546026, 27275.19296144]
l3: [12460.2541769, 12159.7881626, 9517.54482827, 10393.9452616, 25883.7888204, 31826.29595355, 20718.85232457]

Determining Practical Numbers

So I am given a fraction and must determine if the denominator is a practical number. Description of a practical number: What is a practical number?
I already have a function that returns all the factors of the number:
def factorFinder(x):
#Pre: Valid Integer for students
#Post: Returns list of factors for that number
#Takes the number of students as argument and returns all factors for that number
lst = []
for i in range(1, x+1):
if x % i == 0:
lst.append(i)
return(lst)
and a function that given a list of factors as arguments returns a list of sums of all its sublists:
import itertools
def sumsOfSublists(lst):
# Pre: a non-empty list
# Post: returns a list of sums of all possible list sublists of length >= 2
# given a list, returns a sorted list containing sums of
# all combinations of sublists of length 2..list_length
sumList = []
for i in range(2, len(lst)+1):
zlist = list(itertools.combinations(lst,i))
for el in zlist:
sumList.append(sum(el))
return sorted(sumList)
I don't know how to go about testing if the number is practical or not. I don't really understand the concept of a "practical number" even after reading about it on multiple websites. So I guess really, this is more of a math question if anything.
Also given two number I need to print out the egyptian fractions for them. (i.e) given 7/8 should print the following: (1/2)+(1/4)+(1/8). All numerators must be 1.
Looks like you've done all the heavy lifting you just need a check:
def is_practical(n):
s = set(sumsOfSublists(factorFinder(n)))
return all(i in s for i in range(1, n))
Is there any reason you are sorting the sums into a list? sets are much quicker to look up. See https://wiki.python.org/moin/TimeComplexity
I reformulate your wiki-article and hope that it is helpful to you - because as AChampion has said - you have already done all the heavy lifting ;)
n is is a practical number if:
let l = [1, 2, ... n-1] // all number smaller than n
let divs = [i for i in range(1,n) if n%i==0] // all divisors of n (I associate a factor is prime cause of the term factorization of a number, so probably you should change factor to divisor in your question)
Now you have to write all numbers of l as sum of numbers from divs, where you can use all numbers of divs one or zero times
for example n = 12 is a practical number because:
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
divs = [1, 2, 3, 4, 6]
l[0] = divs[0], l[1] = divs[1], ... , l[10] = divs[0]+divs[3]+divs[4]=1+4+6=11 // l[1] = divs[0]+divs[0] is not allowed because you may use each number of divs only once
In opposite n = 3 is not a practical number because:
l = [1, 2]
divs = [1]
l[0] = divs[0], l[1] = mööööp
Here is also a straightforward implementation of my explanation (but you can also keep the nice work you have already done!):
from itertools import combinations
def isPracticalNumber(n):
l = [i for i in range(1, n)]
divs = [i for i in range(1, n) if n % i == 0]
possibleSums = set()
for i in range(1, len(divs)+1):
combinationsOfLengthI = combinations(divs, i)
for combi in combinationsOfLengthI:
possibleSums.add(sum(combi))
return all([i in possibleSums for i in l])
if __name__ == '__main__':
print(isPracticalNumber(12)) # True
print(isPracticalNumber(3)) # False
practicalNumbers = [1, 2, 4, 6, 8, 12, 16, 18, 20, 24, 28, 30, 32, 36, 40, 42, 48, 54, 56, 60, 64, 66, 72, 78, 80, 84, 88, 90, 96, 100, 104, 108, 112, 120, 126, 128, 132, 140, 144, 150]
calculatedPracticalNumbers = [i for i in range(1, 151) if isPracticalNumber(i)]
print(len(calculatedPracticalNumbers) == len(practicalNumbers) and all([i in practicalNumbers for i in calculatedPracticalNumbers]))

Generating a list of EVEN numbers in Python

Basically I need help in generating even numbers from a list that I have created in Python:
[1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, ...]
I have tried a couple different methods, but every time I print, there are odd numbers mixed in with the evens!
I know how to generate even/odd numbers if I were to do a range of 0-100, however, getting only the even numbers from the previous mentioned list has me stumped!
P.S. I've only been using python for a couple days, if this turns out to be extremely simple, thanks in advance!
EDIT: Thanks for all the replies, with your help I've gotten through this little problem.
Here is what I ended up with to complete a little excercise asking to sum the even numbers of fibonacci sequence:
F = [1, 2]
while F[-1] < 4000000
F.append(F[-1] + F[-2])
sum(F[1::3])
4613732
Use a list comprehension (see: Searching a list of objects in Python)
myList = [<your list>]
evensList = [x for x in myList if x % 2 == 0]
This is good because it leaves list intact, and you can work with evensList as a normal list object.
Hope this helps!
The following sample should solve your problem.
Newlist = []
for x in numList:
if x % 2 == 0:
print x
Newlist.append(x)
You can do this with a list comprehension:
evens = [n for n in numbers if n % 2 == 0]
You can also use the filter function.
evens = filter(lambda x: x % 2 == 0,numbers)
If the list is very long it may be desirable to create something to iterate over the list rather than create a copy of half of it using ifilter from itertools:
from itertools import ifilter
evens = ifilter(lambda x: x % 2 == 0,numbers)
Or by using a generator expression:
evens = (n for n in numbers if n % 2 == 0)
In your specific case my_list[1::3] will work. There are always two odd integers between even integers in fibonacci: even, odd, odd, even, odd, odd.....
>>> my_list = [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368]
>>>
...
>>> my_list[1::3]
[2, 8, 34, 144, 610, 2584, 10946, 46368]
Just check this
A = [i for i in range(101)]
B = [x for x in A if x%2 == 0]
print B
iterate through the list and use the modulo operator to check even
for number in list:
if (number % 2) == 0:
##EVEN
Just for fun, checking if number%2 != 1 also works ;)
evens=[x for x in evens_and_odds if number%2 != 1 ]
Note that you can do some clever things to separate out evens and odds in one loop:
evens=[]
odds=[]
numbers=[ evens, odds ]
for x in evens_and_odds:
numbers[x%2 == 1].append(x)
print evens
print odds
The above trick works because logical expressions (==, >, etc.) operating on numbers True (1) and/or False (0).
You can use list comprehension to generate a new list that contains only the even members from your original list.
data = [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
then:
new_data = [i for i in data if not i%2]
yields
[2, 8, 34, 144]
Or alternatively use a generator expression if you don't need all of the numbers
at once:
new_data = (i for i in data if not i%2)
The values then would be availabe as needed, for instance if you used a for loop:
e.g.,
for val in new_data:
print val
The advantage of the generator expression is that the whole list is not generated and stored in memory at once, but values are generated as you need them which makes less demand on memory. There are other important differences you might want to read up on at some point if you are interested.
Instead of generating all Fibonacci numbers then filtering for evens, why not generate just the even values?
def even_fibs():
a,b = 1,2
while True:
yield b
a,b = a+2*b, 2*a+3*b
generates [2, 8, 34, 144, 610, 2584, 10946 ...]
then your sum code becomes:
total = 0
for f in even_fibs():
if f >= 4000000:
break
else:
total += f
or
from itertools import takewhile
total = sum(takewhile(lambda n: n<4000000, even_fibs()))
a = range(0,1000)
b = []
for c in a:
if c%2==0:
b.append(c)
print b
You could do this using the filter function as follows:
F = [1, 2]
while F[-1] < 4000000:
F.append(F[-1] + F[-2])
print(F)
print('\n')
#create the variable that could store the sorted values from the list you have created.
sorted_number=list(filter(lambda x:x%2==0,F))
print(sorted_number)
You could use a for and if loop using the length function, like this:
for x in range(len(numList)):
if x%2 == 0:
print(x)
NewList.append(x)
Basically you should create a variable and put your list in and then sort your even numbers list by adding it only the even numbers
numbers = [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, ...]
even = [e for e in numbers if e%2==0]
Here are some of the different ways to get even numbers:
CASE 1
in this case, you have to provide a range
lst = []
for x in range(100):
if x%2==0:
lst.append(x)
print(lst)
CASE 2
this is a function and you have to pass a parameter to check if it is an even no or not
def even(rangeno):
for x in range(rangeno):
if rangeno%2 == 0:
return rangeno
else:
return 'No an Even No'
even(2)
CASE 3
checking the values in the range of 100 to get even numbers through function with list comprehension
def even(no):
return [x for x in range(no) if x%2==0]
even(100)
CASE 4
This case checks the values in list and prints even numbers through lambda function. and this case is suitable for the above problem
lst = [2,3,5,6,7,345,67,4,6,8,9,43,6,78,45,45]
no = list(filter(lambda x: (x % 2 == 0), lst))
print(no)

Categories

Resources