how to pass the result of one function to another? - python

i am beginner of python and i have a question. How to pass the result of one
function to another one. I want to make new list based on first one only with prime digits, and when i run my program second list is empty
def get_list_of_int_numbers(n: int):
list1 = [random.randint(10, 100) for x in range(random.randint(10, 100))] * n
return list1
def get_prime_digits(n: int) -> bool:
return n in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97.]
def get_second_list_based_on_old_one_with_prime_digits(expression: list) -> list:
list2 = [n for n in expression if n == get_prime_digits(n)]
return list2
def main() -> None:
n1 = random.randint(10, 100)
print(get_list_of_int_numbers(n1))
print(get_second_list_based_on_old_one_with_prime_digits(get_list_of_int_numbers(n1)))
if __name__ == '__main__':
main()
any help would be appreciated

Problem is in your get_second_list_based_on_old_one_with_prime_digits, you don't need to use n to compare with the result of get_prime_digits
def get_second_list_based_on_old_one_with_prime_digits(expression: list) -> list:
list2 = [n for n in expression if n == get_prime_digits(n)]
# ^^^^
return list2

Well, I don't know why the second printed list would always be empty but it will certainly not be using the values created in your first call to get_list_of_int_numbers(...).
This is because you are not saving the results of the first call to get_list_of_int_numbers(...) into a variable. And the second call to it, creates a different list.
def main() -> None:
n1 = random.randint(10, 100)
new_list : list = get_list_of_int_numbers(n1) # Save first list here
print(get_second_list_based_on_old_one_with_prime_digits(new_list)) # Reuse first list

There are two main issues with your code.
First, you are not saving the result of your first call to get_list_of_int_numbers .
Second, your get_second_list_based_on_old_one_with_prime_digits function compares n == get_prime_digits(n), which will always be false b/c get_prime_digits returns a bool.
Something like:
def get_second_list_based_on_old_one_with_prime_digits(expression: list) -> list:
list2 = [n for n in expression if get_prime_digits(n)]
return list2
def main() -> None:
n1 = random.randint(10, 100)
n1_list = get_list_of_int_numbers(n1)
print(n1_list)
print(get_second_list_based_on_old_one_with_prime_digits(n1_list))
should work better for you.

Related

Trying to swap the first and last elements of a list in Python, but it works only for a predefined list. Not for a list of randomly generated numbers

I was trying to create a python program which swaps the first and last elements of a list. I passed a pre-created list into the algorithm and it worked perfectly. Here's my code:
def swapFirstAndLast(list_to_be_swapped):
size = len(list_to_be_swapped)
list_to_be_swapped[0],list_to_be_swapped[size-1] = list_to_be_swapped[size-1],list_to_be_swapped[0]
return list_to_be_swapped
l = [12,33,42,76,46,97]
swapFirstAndLast(l)
print(l)
Output:
[97, 33, 42, 76, 46, 12]
Then I tried to create functions; one function to create a list of randomly generated numbers, and the second function to perform the swapping operation. Although everything makes sense to me, it is not performing the swapping operation now. This is the code I came up with:
import random
def generateList(size):
list1 = []
for i in range(size):
list1.append(random.randint(0,99))
return list1
def swapFirstAndLast(list_to_be_swapped):
size = len(list_to_be_swapped)
list_to_be_swapped[0],list_to_be_swapped[size-1] = list_to_be_swapped[size-1],list_to_be_swapped[0]
return list_to_be_swapped
l = generateList(5)
l1 = swapFirstAndLast(l)
print(l,l1)
Output:
[49, 78, 63, 82, 72] [49, 78, 63, 82, 72]
As you can see, it does not perform the swapping operation now. I am not able to understand where I am going wrong.
You are swapping the first and the last element of the initial list (i.e., l) too! Please look at this slightly modified example:
import random
def generateList(size):
list1 = []
for i in range(size):
list1.append(random.randint(0,99))
return list1
def swapFirstAndLast(list_to_be_swapped):
size = len(list_to_be_swapped)
list_to_be_swapped[0],list_to_be_swapped[size-1] = list_to_be_swapped[size-1],list_to_be_swapped[0]
return list_to_be_swapped
l = generateList(5)
print(l)
l1 = swapFirstAndLast(l)
print(l, l1)
Output:
[54, 14, 3, 38, 87]
[87, 14, 3, 38, 54] [87, 14, 3, 38, 54]
As you can see, the list l has been changed.
The thing here is that you are not creating a new list, but you're modifying the existing one. It doesn't matter if it has a different name within the function.
If you want to retain the original list l, and also return a separate swapped list l1, you have to create a new list! Here is how you can do it:
import random
def generateList(size):
return [random.randint(0, 99) for _ in range(size)]
def swapFirstAndLast(list_to_be_swapped):
new_list = list_to_be_swapped.copy()
new_list[0], new_list[-1] = new_list[-1], new_list[0]
return new_list
l = generateList(5)
print(l)
l1 = swapFirstAndLast(l)
print(l, l1)
Output:
[38, 59, 86, 26, 19]
[38, 59, 86, 26, 19] [19, 59, 86, 26, 38]
your program works ! your function just modifies the list directly, you can see it better if you do this :
l = generateList(5)
print(l)
l1 = swapFirstAndLast(l)
print(l1)
It turns out that you have already swapped the list (i.e. l) it's just when your print (l,l1) that it looks like you haven't swapped it because it's printing the swapped version of (l). put the print(l) line above ( l1 = swapFirstAndLast(l) ) to see it!
the swapping can be done by using index:
def swapFirstAndLast(lst):
lst[0], lst[-1] = lst[-1], lst[0]
return lst
lst = [12,33,42,76,46,97]
print(swapFirstAndLast(lst))
result is: [97, 33, 42, 76, 46, 12]

Given a list of numbers, how can I remove all multiples of primes (but not primes)?

I am starting on my Python journey and am doing some exercises to get the hang of it all. One question is really giving me troubles as I do not understand how to complete it.
Question:
Given a list of natural numbers, remove from it all multiples of 2 (but not 2), multiples of 3 (but not 3), and so on, up to the multiples of 100, and print the remaining values.
From this question I take it that I should first make a list with all prime numbers and after that append the values that correspond to a new list. This is what I have until know:
# Read list:
a = [5, 6, 7, 8, 9]
# First get a list with all primes
primes = []
for i in range(0, 101):
for j in range(2, int(i ** 0.5) + 1):
if i%j == 0:
break
else:
primes.append(i)
# Next append to new list
b = []
for num in a:
for prime in primes:
if num == prime and num % prime == 0:
b.append(num)
print(b)
Now this works for this simple example, but upon testing it on another set (one of which I do not know the input values of the test case), my output is:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
Which is my original list with the prime numbers. So somewhere along the line I am making a mistake and I cannot see the logic behind it. Any help would be greatly appreciated.
To solve the task all you need to do is filter out the numbers by using a generator and a for loop, which by itself is already finding the prime numbers
a = [5,6,7,8,9]
for i in range(2,101):
a = [j for j in a if (j==i or j%i!=0)]

Explain list comprehension in cumulative sum of list

Python code to get the Cumulative sum of a list
def Cumulative(lists):
cu_list = []
length = len(lists)
cu_list = [sum(lists[0:x:1]) for x in range(0, length+1)]
return cu_list[1:]
# Driver Code
lists = [10, 20, 30, 40, 50]
print (Cumulative(lists))
Can anyone help me to expand above list comprehension ?
I have written this code
def cum_sum(m):
result = 0
for x in m:
result += x
print(result, end=", ")
cum_sum([1,2,3,10])
This is the expanded form of the list comprehension:
cu_list = []
for x in range(0, length+1):
s = sum(lists[0:x:1])
cu_list.append(s)
use a generator
def cum_sum(m):
result = 0
for x in m:
result += x
yield result
list(cum_sum([1,2,3,10]))
ans = []
for i in range(len(lists)):
ans.append(sum(lists[:i+1]))
this part of your code
[sum(lists[0:x:1]) for x in range(0, length+1)]
creates a new list starting from the first element of lists up to (and excluding) the x'th element of your list (see e.g. Python List Slicing). then it takes the sum over it.
so it unnecessarily creates several lists and does unnecessary sums (it could keep the sum up to element x in memory and just add the next element - as do most solutions presented here).
you get that for free with itertools.accumulate already:
from itertools import accumulate
lists = [10, 20, 30, 40, 50]
print(list(accumulate(lists)))
# [10, 30, 60, 100, 150]

add neigbouring elements in a list

How can I write a function which takes a list of integers and creates a new list with the same number of elements as the original list such that each integer in the new list is the sum of its neighbours and itself in the original list. For example, if a_list = [10, 20, 30, 40, 50], the new_list = [30, 60, 90, 120, 90].
I tried a list comprehension;
def sum_neighbours(a_list):
b_list = a_list
li = [x+y for x in a_list for y in b_list]
return li
print(sum_neighbours([10, 20, 30, 40, 50]))
Which gave me;
[20, 30, 40, 50, 60, 30, 40, 50, 60, 70, 40, 50,
60, 70, 80, 50, 60, 70, 80, 90, 60, 70, 80, 90, 100]
I then tried a for loop;
def sum_neighbours(a_list):
element1 = a_list[0]
new_list = []
for element in a_list:
element1 += element
new_list += element1
return new_list
print(sum_neighbours([10,20,30,40,50]))
Which threw a TypeError: 'int' object is not iterable
But in both cases I don't think my ideas/attempts are on the right track... I would really appreciate any help, hints, tips that more experienced people may have.
You can start with a solution that iterates through the indexes of the list, like so:
def sum_neighbours1(a_list):
result = []
for i in range(len(a_list)):
if i == 0:
result.append(a_list[i] + a_list[i+1])
elif i == len(a_list)-1:
result.append(a_list[i-1] + a_list[i])
else:
result.append(a_list[i-1] + a_list[i] + a_list[i+1])
return result
print(sum_neighbours1([10,20,30,40,50]))
Or, you can build three distinct lists: the original list, the list of left-hand neighbors, and the list of right-hand neighbors. We have to put 0 at the front or rear of the auxiliary lists. Each of the lists must be at least as long as the original list.
Zip the three lists together, and add them:
def sum_neighbours2(a_list):
priors = [0] + a_list
subsequents = a_list[1:] + [0]
return map(sum, zip(priors, a_list, subsequents))
Note that I used the functional notation map(sum, data), but I could have used a list conprehension just as easily:
def sum_neighbours3(a_list):
priors = [0] + a_list
subsequents = a_list[1:] + [0]
return [p+a+s for p,a,s in zip(priors, a_list, subsequents)]
And, if I were eager to make the result a single expression (for example, if it had to fit in a lambda expression), here that is:
def sum_neighbours4(a_list):
return [
left + a + right
for left, a, right in zip(
[0] + a_list,
a_list,
a_list[1:] + [0])
]
Here is my one line solution with zip :
def sum_neighbours(a) :
return [sum(x) for x in [(a[0],a[1])]+zip(a,a[1:],a[2:])+[(a[-2],a[-1])]]
print sum_neighbours([10, 20, 30, 40, 50]) # display [30, 60, 90, 120, 90]
with :
a, the original list
zip(a,a[1:],a[2:]), 3-tuples generation
[(a[0],a[1])] and [(a[-2],a[-1])], 2-tuples for particular cases (first and last numbers of list)
You'll probably want a for i in range loop, and indexing directly into the array so you can look at the element that is at i+1 and i-1 indexes (making sure to check that your +/- 1 isn't going outside the bounds of the array).

Interpreting Number Ranges in Python

In a Pylons webapp, I need to take a string such as "<3, 45, 46, 48-51, 77" and create a list of ints (which are actually IDs of objects) to search on.
Any suggestions on ways to do this? I'm new to Python, and I haven't found anything out there that helps with this kind of thing.
The list would be: [1, 2, 3, 45, 46, 48, 49, 50, 51, 77]
Use parseIntSet from here
I also like the pyparsing implementation in the comments at the end.
The parseIntSet has been modified here to handle "<3"-type entries and to only spit out the invalid strings if there are any.
#! /usr/local/bin/python
import sys
import os
# return a set of selected values when a string in the form:
# 1-4,6
# would return:
# 1,2,3,4,6
# as expected...
def parseIntSet(nputstr=""):
selection = set()
invalid = set()
# tokens are comma seperated values
tokens = [x.strip() for x in nputstr.split(',')]
for i in tokens:
if len(i) > 0:
if i[:1] == "<":
i = "1-%s"%(i[1:])
try:
# typically tokens are plain old integers
selection.add(int(i))
except:
# if not, then it might be a range
try:
token = [int(k.strip()) for k in i.split('-')]
if len(token) > 1:
token.sort()
# we have items seperated by a dash
# try to build a valid range
first = token[0]
last = token[len(token)-1]
for x in range(first, last+1):
selection.add(x)
except:
# not an int and not a range...
invalid.add(i)
# Report invalid tokens before returning valid selection
if len(invalid) > 0:
print "Invalid set: " + str(invalid)
return selection
# end parseIntSet
print 'Generate a list of selected items!'
nputstr = raw_input('Enter a list of items: ')
selection = parseIntSet(nputstr)
print 'Your selection is: '
print str(selection)
And here's the output from the sample run:
$ python qq.py
Generate a list of selected items!
Enter a list of items: <3, 45, 46, 48-51, 77
Your selection is:
set([1, 2, 3, 45, 46, 77, 48, 49, 50, 51])
I've created a version of #vartec's solution which I feel is more readable:
def _parse_range(numbers: str):
for x in numbers.split(','):
x = x.strip()
if x.isdigit():
yield int(x)
elif x[0] == '<':
yield from range(0, int(x[1:]))
elif '-' in x:
xr = x.split('-')
yield from range(int(xr[0].strip()), int(xr[1].strip())+1)
else:
raise ValueError(f"Unknown range specified: {x}")
In the process, the function became a generator :)
rng = "<3, 45, 46, 48-51, 77"
ids = []
for x in map(str.strip,rng.split(',')):
if x.isdigit():
ids.append(int(x))
continue
if x[0] == '<':
ids.extend(range(1,int(x[1:])+1))
continue
if '-' in x:
xr = map(str.strip,x.split('-'))
ids.extend(range(int(xr[0]),int(xr[1])+1))
continue
else:
raise Exception, 'unknown range type: "%s"'%x
First, you'll need to figure out what kind of syntax you'll accept. You current have three in your example:
Single number: 45, 46
Less than operator
Dash ranging: 48-51
After that, it's just a matter of splitting the string into tokens, and checking the format of the token.
I also had to do something similar for an app lately.
If you don't need concrete numbers but just a way to see whether a given number is in the range, you might consider parsing it to a Python expression you can eval into a lambda. For example <3, 5-10, 12 could be func=(lambda x:x<3 or (5 <= x <= 10) or x==12)). Then you can just call the lambda, func(11) to see if 11 belongs in there.
>>> print range.__doc__
range([start,] stop[, step]) -> list of integers
Return a list containing an arithmetic progression of integers.
range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.
When step is given, it specifies the increment (or decrement).
For example, range(4) returns [0, 1, 2, 3]. The end point is omitted!
These are exactly the valid indices for a list of 4 elements.
>>> range(33,44)
[33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43]
>>> range(1,3)
[1, 2]
I imagine you could iterate your list, and call range appropriately.
>>> def lessThan(n) :
... return range(n+1)
...
>>> lessThan(4)
[0, 1, 2, 3, 4]
>>> def toFrom(n,m):
... return range(n,m)
...
>>> toFrom(33,44)
[33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43]
Then split the string on commas, and for each bit, parse it enough to figure out what function to call, catenating the lists returned.
Anything more and I'd have written it for you.

Categories