Cumulative product of a list - python

I have implemented a list of all prime numbers from a set amount.
What I'm trying to do is hard to explain so I'll just show it with some hard code:
euclst = []
euclst.append((primelst[0]) + 1)
euclst.append((primelst[0] * primelst[1]) + 1)
euclst.append((primelst[0] * primelst[1] * primelst[2]) + 1)
....
So essentially I'm trying to take a single element in order from my prev list and multiplying it exponentially I guess and appending it to my other list.
I realized that I could just do this, which is probably easier:
euclst = []
euclst.append(primelst[0])
euclst.append(primelst[0] * primelst[1])
euclst.append(primelst[0] * primelst[1] * primelst[2])
....
#then add one to each element in the list later
I need some ideas to do this in a loop of some sort.

You want a list of the cumulative product. Here's a simple recipe:
>>> primelist = [2, 3, 5, 7, 11, 13, 17, 19, 23]
>>> euclist = []
>>> current = 1
>>> for p in primelist:
... current *= p
... euclist.append(current)
...
>>> euclist
[2, 6, 30, 210, 2310, 30030, 510510, 9699690, 223092870]
>>>
Another way, using itertools:
>>> import itertools
>>> import operator
>>> list(itertools.accumulate(primelist, operator.mul))
[2, 6, 30, 210, 2310, 30030, 510510, 9699690, 223092870]
>>>
OR, perhaps this is what you mean:
>>> [x + 1 for x in itertools.accumulate(primelist, operator.mul)]
[3, 7, 31, 211, 2311, 30031, 510511, 9699691, 223092871]
With the equivalent for-loop:
>>> euclist = []
>>> current = 1
>>> for p in primelist:
... current = current*p
... euclist.append(current + 1)
...
>>> euclist
[3, 7, 31, 211, 2311, 30031, 510511, 9699691, 223092871]
>>>

You could do it like this:
euclst = [primelst[0]]
for p in primelst[1:]:
euclst.append(euclst[-1]*p)
initialize your list with first element
loop and append the current element with the previous appended element
(since current result depends on previous results, it's not easily doable in a list comprehension)
To solve the more complex one with a +1 on it:
euclst = [primelst[0]+1]
for p in primelst[1:]:
euclst.append((euclst[-1]-1)*p+1)
(the previous result is the product plus one, so to reuse it, just substract one)
EDIT: other answers make me realize that I'm overcomplicating things. A temp variable to store the cumulative product would probably be cleaner.

It might be clearest to use an intermediate variable to keep track of the product, and then add the 1 as you put it in the list.
euclst = []
running_prod = 1
for p in primelst[]:
running_prod *= p
euclst.append(running_prod + 1)

you can use something like this:
euclst.append(primelst[0])
euclst.append(euclst[-1]*primelst[i])

Related

How can you find the maximum nth integer in a list in python? [duplicate]

I know how to find the 1st highest value but don't know the rest. Keep in mind i need to print the position of the 1st 2nd and 3rd highest value.Thank You and try to keep it simple as i have only been coding for 2 months. Also they can be joint ranks
def linearSearch(Fscore_list):
pos_list = []
target = (max(Fscore_list))
for i in range(len(Fscore_list)):
if Fscore_list[i] >= target:
pos_list.append(i)
return pos_list
This will create a list of the 3 largest items, and a list of the corresponding indices:
lst = [9,7,43,2,4,7,8,5,4]
values = []
values = zip(*sorted( [(x,i) for (i,x) in enumerate(f_test)],
reverse=True )[:3] )[0]
posns = []
posns = zip(*sorted( [(x,i) for (i,x) in enumerate(f_test)],
reverse=True )[:3] )[1]
Things are a bit more complicated if the same value can appear multiple times (this will show the highest position for a value):
lst = [9,7,43,2,4,7,8,5,4]
ranks = sorted( [(x,i) for (i,x) in enumerate(lst)], reverse=True
)
values = []
for x,i in ranks:
if x not in values:
values.append( x )
posns.append( i )
if len(values) == 3:
break
print zip( values, posns )
Use heapq.nlargest:
>>> import heapq
>>> [i
... for x, i
... in heapq.nlargest(
... 3,
... ((x, i) for i, x in enumerate((0,5,8,7,2,4,3,9,1))))]
[7, 2, 3]
Add all the values in the list to a set. This will ensure you have each value only once.
Sort the set.
Find the index of the top three values in the set in the original list.
Make sense?
Edit
thelist = [1, 45, 88, 1, 45, 88, 5, 2, 103, 103, 7, 8]
theset = frozenset(thelist)
theset = sorted(theset, reverse=True)
print('1st = ' + str(theset[0]) + ' at ' + str(thelist.index(theset[0])))
print('2nd = ' + str(theset[1]) + ' at ' + str(thelist.index(theset[1])))
print('3rd = ' + str(theset[2]) + ' at ' + str(thelist.index(theset[2])))
Edit
You still haven't told us how to handle 'joint winners' but looking at your responses to other answers I am guessing this might possibly be what you are trying to do, maybe? If this is not the output you want please give us an example of the output you are hoping to get.
thelist = [1, 45, 88, 1, 45, 88, 5, 2, 103, 103, 7, 8]
theset = frozenset(thelist)
theset = sorted(theset, reverse=True)
thedict = {}
for j in range(3):
positions = [i for i, x in enumerate(thelist) if x == theset[j]]
thedict[theset[j]] = positions
print('1st = ' + str(theset[0]) + ' at ' + str(thedict.get(theset[0])))
print('2nd = ' + str(theset[1]) + ' at ' + str(thedict.get(theset[1])))
print('3rd = ' + str(theset[2]) + ' at ' + str(thedict.get(theset[2])))
Output
1st = 103 at [8, 9]
2nd = 88 at [2, 5]
3rd = 45 at [1, 4]
BTW : What if all the values are the same (equal first) or for some other reason there is no third place? (or second place?). Do you need to protect against that? If you do then I'm sure you can work out appropriate safety shields to add to the code.
Jupyter image of the code working
This question was on my Udemy machine learning course way too soon. Scott Hunter helped me the most on this problem, but didn't get me to a pass on the site. Having to really think about the issue deeper on my own. Here is my solution, since couldn't find it anywhere else online--in terms that I understood everything that was going on*:
lst = [9,7,43,2,4,7,8,9,4]
ranks = sorted( [(x,i) for (i,x) in enumerate(lst)], reverse=True )
box = []
for x,i in ranks:
if i&x not in box:
box.append( x )
if len(box) == 3:
break
print(box)
So we have a list of numbers. To rank the numbers we sort the value with its position for every position that has a value when we enumerate/iterate the list. Then we put the highest values on top by reversing it. Now we need a box to put our information in to pull out of later, so we build that box []. Now for every value with a position put that in the box, if the value and position isn't already in the box--meaning if the value is already in the box, but the position isn't, still put in the box. And we only want three answers. Finally tell me what is in the variable called box.
*Many of these answers, on this post, will most likely work.
Input : [4, 5, 1, 2, 9]
N = 2
Output : [9, 5]
Input : [81, 52, 45, 10, 3, 2, 96]
N = 3
Output : [81, 96, 52]
# Python program to find N largest
# element from given list of integers
l = [1000,298,3579,100,200,-45,900]
n = 4
l.sort()
print(l[-n:])
Output:
[298, 900, 1000, 3579]
lst = [9,7,43,2,4,7,8,9,4]
temp1 = lst
print(temp1)
#First Highest value:
print(max(temp1))
temp1.remove(max(temp1))
#output: 43
# Second Highest value:
print(max(temp1))
temp1.remove(max(temp1))
#output: 9
# Third Highest Value:
print(max(temp1))
#output: 7
There's a complicated O(n) algorithm, but the simplest way is to sort it, which is O(n * log n), then take the top. The trickiest part here is to sort the data while keeping the indices information.
from operator import itemgetter
def find_top_n_indices(data, top=3):
indexed = enumerate(data) # create pairs [(0, v1), (1, v2)...]
sorted_data = sorted(indexed,
key=itemgetter(1), # sort pairs by value
reversed=True) # in reversed order
return [d[0] for d in sorted_data[:top]] # take first N indices
data = [5, 3, 6, 3, 7, 8, 2, 7, 9, 1]
print find_top_n_indices(data) # should be [8, 5, 4]
Similarly, it can be done with heapq.nlargest(), but still you need to pack the initial data into tuples and unpack afterwards.
To have a list filtered and returned in descending order with duplicates removed try using this function.
You can pass in how many descending values you want it to return as keyword argument.
Also a side note, if the keyword argument (ordered_nums_to_return) is greater than the length of the list, it will return the whole list in descending order. if you need it to raise an exception, you can add a check to the function. If no args is passed it will return the highest value, again you can change this behaviour if you need.
list_of_nums = [2, 4, 23, 7, 4, 1]
def find_highest_values(list_to_search, ordered_nums_to_return=None):
if ordered_nums_to_return:
return sorted(set(list_to_search), reverse=True)[0:ordered_nums_to_return]
return [sorted(list_to_search, reverse=True)[0]]
print find_highest_values(list_of_nums, ordered_nums_to_return=4)
If values can appear in your list repeatedly you can try this solution.
def search(Fscore_list, num=3):
l = Fscore_list
res = dict([(v, []) for v in sorted(set(l), reverse=True)[:num]])
for index, val in enumerate(l):
if val in res:
res[val].append(index)
return sorted(res.items(), key=lambda x: x[0], reverse=True)
First it find num=3 highest values and create dict with empty list for indexes for it. Next it goes over the list and for every of the highest values (val in res) save it's indexes. Then just return sorted list of tuples like [(highest_1, [indexes ...]), ..]. e.g.
>>> l = [9, 7, 43, 2, 4, 7, 43, 8, 5, 8, 4]
>>> print(search(l))
[(43, [2, 6]), (9, [0]), (8, [7, 9])]
To print the positions do something like:
>>> Fscore_list = [9, 7, 43, 2, 4, 7, 43, 8, 5, 8, 4, 43, 43, 43]
>>> result = search(Fscore_list)
>>> print("1st. %d on positions %s" % (result[0][0], result[0][1]))
1st. 43 on positions [2, 6, 11, 12, 13]
>>> print("2nd. %d on positions %s" % (result[1][0], result[1][1]))
2nd. 9 on positions [0]
>>> print("3rd. %d on positions %s" % (result[2][0], result[2][1]))
3rd. 8 on positions [7, 9]
In one line:
lst = [9,7,43,2,8,4]
index = [i[1] for i in sorted([(x,i) for (i,x) in enumerate(lst)])[-3:]]
print(index)
[2, 0, 1]
None is always considered smaller than any number.
>>> None<4
True
>>> None>4
False
Find the highest element, and its index.
Replace it by None. Find the new highest element, and its index. This would be the second highest in the original list. Replace it by None. Find the new highest element, which is actually the third one.
Optional: restore the found elements to the list.
This is O(number of highest elements * list size), so it scales poorly if your "three" grows, but right now it's O(3n).

How do I generate a list of all possible combinations from a single element in a pair, from numerous pairs nested within a parent list?

I find myself in a unique situation in which I need to multiply single elements within a listed pair of numbers where each pair is nested within a parent list of elements. For example, I have my pre-defined variables as:
output = []
initial_list = [[1,2],[3,4],[5,6]]
I am trying to calculate an output such that each element is the product of a unique combination (always of length len(initial_list)) of a single element from each pair. Using my example of initial_list, I am looking to generate an output of length pow(2 * len(initial_list)) that is scable for any "n" number of pairs in initial_list (with a minimum of 2 pairs). So in this case each element of the output would be as follows:
output[0] = 1 * 3 * 5
output[1] = 1 * 3 * 6
output[2] = 1 * 4 * 5
output[3] = 1 * 4 * 6
output[4] = 2 * 3 * 5
output[5] = 2 * 3 * 6
output[6] = 2 * 4 * 5
output[7] = 2 * 4 * 6
In my specific case, the order of output assignments does not matter other than output[0], which I need to be equivalent to the product of the first element in each pair in initial_list. What is the best way to proceed to generate an output list such that each element is a unique combination of every element in each list?
...
My initial approach consisted of using;
from itertools import combinations
from itertools import permutations
from itertools import product
to somehow generate a list of every possible combination then multiply the products together and append each product to the output list, but I couldn't figure out a wait to implement the tools successfully. I have since tried to create a recursive function that combines for x in range(2): with nested recursion recalls, but once again I cannot figured out a solution.
Someone more experienced and smarter than me please help me out; Any and all help is appreciated! Thank you!
Without using any external library
def multi_comb(my_list):
"""
This returns the multiplication of
every possible combinationation of
the `my_list` of type [[a1, a2], [b1, b2], ...]
Arg: List
Return: List
"""
if not my_list: return [1]
a, b = my_list.pop(0)
result = multi_comb(my_list)
left = [a * i for i in result]
right = [b * i for i in result]
return (left + right)
print(multi_comb([[1, 2], [3, 4], [5, 6]]))
# Output
# [15, 18, 20, 24, 30, 36, 40, 48]
I am using reccursion to get the result. Here's the visual illustration of how this works.
Instead of taking a top-down approach, we can take bottom-up approach to better understand how this program works.
At the last step, a and b becomes 5 and 6 respectively. Calling multi_comb() with empty list returns [1] as a result. So left and right becomes [5] and [6]. Thus we return [5, 6] to our previous step.
At the second last step, a and b was 3 and 4 respectively. From the last step we got [5, 6] as a result. After multiplying each of the values inside the result with a and b (notice left and right), we return the result [15, 18, 20, 24] to our previous step.
At our first step, that is our starting step, we had a and b as 1 and 2 respectively. The value returned from our last step becomes our result, ie, [15, 18, 20, 24]. Now we multiply both a and b with this result and return our final output.
Note:
This program works only if list is in the form [ [a1, a2], [b1, b2], [c1, c2], ... ] as told by the OP in the comments. The problem of solving the list containing the sub-list of n items will be little different in code, but the concept is same as in this answer.
This problem can also be solved using dynamic programming
output = [1, ]
for arr in initial_list:
output = [a * b for a in arr for b in product]
This problem is easy to solve if you have just one subarray -- the output is the given subarray.
Suppose you solved the problem for the first n - 1 subarrays, and you got the output. The new subarray is appended. How the output should change? The new output is all pair-wise products of the previous output and the "new" subarray.
Look closely, there's an easy pattern. Let there be n sublists, and 2 elements in each: at index 0 and 1. Now, the indexes selected can be represented as a binary string of length n.
It'll start with 0000..000, then 0000...001, 0000...010 and so on. So all you need to do is:
n = len(lst)
for i in range(2**n):
binary = bin(i)[2:] #get binary representation
for j in range(n):
if binary[j]=="1":
#include jth list's 1st index in product
else:
#include jth list's 0th index in product
The problem would a scalable solution would be, since you're generating all possible pairs, the time complexity will be O(2^N)
Your idea to use itertools.product is great!
import itertools
initial_list = [[1,2],[3,4],[5,6]]
combinations = list(itertools.product(*initial_list))
# [(1, 3, 5), (1, 3, 6), (1, 4, 5), (1, 4, 6), (2, 3, 5), (2, 3, 6), (2, 4, 5), (2, 4, 6)]
Now, you can get the product of each tuple in combination using for-loops, or using functools.reduce, or you can use math.prod which was introduced in python 3.8:
import itertools
import math
initial_list = [[1,2],[3,4],[5,6]]
output = [math.prod(c) for c in itertools.product(*initial_list)]
# [15, 18, 20, 24, 30, 36, 40, 48]
import itertools
import functools
import operator
initial_list = [[1,2],[3,4],[5,6]]
output = [functools.reduce(operator.mul, c) for c in itertools.product(*initial_list)]
# [15, 18, 20, 24, 30, 36, 40, 48]
import itertools
output = []
for c in itertools.product(*initial_list):
p = 1
for x in c:
p *= x
output.append(p)
# output == [15, 18, 20, 24, 30, 36, 40, 48]
Note: if you are more familiar with lambdas, operator.mul is pretty much equivalent to lambda x,y: x*y.
itertools.product and math.prod are a nice fit -
from itertools import product
from math import prod
input = [[1,2],[3,4],[5,6]]
output = [prod(x) for x in product(*input)]
print(output)
[15, 18, 20, 24, 30, 36, 40, 48]

python-writing q as a function of i in a for loop

I'm completely new to python so forgive me if this question is stupid.I am try to code for a Fibonacci sequence and wanted to know if there is a way for me to write q as a function of i in a for loop.
like:
for i in range (1,x):
q(i)=q(i-1)+q(i-2)
With lists
Yes, you can do that:
>>> x = 10
>>> q = 10*[1]
>>> for i in range(2,x):
... q[i] = q[i-1] + q[i-2]
...
>>> q
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
Notes:
Subscripts in python are denoted with square brackets not parens.
Because the calculation needs q[i-2], the calculation needs to start at index i=2.
With functions
>>> def qfn(i):
... return 1 if i <=1 else qfn(i-1) + qfn(i-2)
...
>>> qfn(8)
34
>>> qfn(9)
55

Python: form a list based on the same values

consider x = [10,10,20,20,20,30]
How do i form another list_x1 which contains only same values example: list_x1 = [10,10]
and list_x2 =[20,20] and list_x3 =[30] ?
You can use counter.
from collections import Counter
x = [10, 10, 20, 20, 20, 30]
my_counter = Counter(x)
d = {'list_x{0}'.format(key): [key] * my_counter[key] for key in my_counter}
>>> d
{'list_x10': [10, 10], 'list_x20': [20, 20, 20], 'list_x30': [30]}
One of the issues with your request is that you would need to pre-assign variables, which aren't initially know. I've used a dictionary as a container to hold them.
For a list, [10] * 3 results in [10, 10, 10]. So, [k] * my_counter multiplies the unique key value by the number of occurrences.
With itertools.groupby
>>> from itertools import groupby
>>> x = [10,10,20,20,20,30]
>>> [list(g) for k, g in groupby(x)]
[[10, 10], [20, 20, 20], [30]]
Perhaps the best way is #Alexander's idea with collections, but I always find it helpful to look at more 'native' python code to see what's going on. So here's a way to do it:
x = [10,10,20,20,20,30]
def foo(iterable):
for val in iterable:
cnt = iterable.count(val)
iterable = list(filter(lambda x: x != val, iterable))
if cnt:
yield [val]*cnt
for _ in foo(x):
print(_)
Note that the complexity factor is going to be fairly high. Certainly not O(n) because you have to:
Iterate through each of the values in our main for val in iterable
Iterate through each of the values every time we call iterable.count
Iterate through each of the values when we filter() them to prevent duplicates.
Using collections.Counter:
>>> def list_gen(in_list, elem):
... count = collections.Counter(in_list)
... return [elem] * count[elem]
...
>>> a
[1, 2, 3, 2, 3]
>>> list_gen(a, 2)
[2, 2]
This isn't exactly what you're looking for, but this code will generate a list of lists separating the values.
x = [10, 10, 20, 20, 20, 30]
uniques = set(x)
output = []
for unique in uniques:
unique_count = x.count(unique)
temp = []
for i in range(0, unique_count):
temp.append(unique)
output.append(temp)
You can then use list comprehensions on output

Permutations in python 2.5.2

I have a list of numbers for input, e.g.
671.00
1,636.00
436.00
9,224.00
and I want to generate all possible sums with a way to id it for output, e.g.:
671.00 + 1,636.00 = 2,307.00
671.00 + 436.00 = 1,107.00
671.00 + 9,224.00 = 9,224.00
671.00 + 1,636.00 + 436.00 = 2,743.00
...
and I would like to do it in Python
My current constrains are:
a) I'm just learning python now (that's part of the idea)
b) I will have to use Python 2.5.2 (no intertools)
I think I have found a piece of code that may help:
def all_perms(str):
if len(str) <=1:
yield str
else:
for perm in all_perms(str[1:]):
for i in range(len(perm)+1):
#nb str[0:1] works in both string and list contexts
yield perm[:i] + str[0:1] + perm[i:]
( from these guys )
But I'm not sure how to use it in my propose.
Could someone trow some tips and pieces of code of help?
cheers,
f.
Permutations are about taking an ordered set of things and moving these things around (i.e. changing order). Your question is about combinations of things from your list.
Now, an easy way of enumerating combinations is by mapping entries from your list to bits in a number. For example, lets assume that if bit #0 is set (i.e. 1), then number lst[0] participates in the combination, if bit #1 is set, then lst[1] participates in the combination, etc. This way, numbers in range 0 <= n < 2**(len(lst)) identify all possible combinations of lst members, including an empty one (n = 0) and the whole lst (n = 2**(len(lst)) - 1).
You need only combinations of 2 items or more, i.e. only those combination IDs that have at least two nonzero bits in their binary representation. Here is how to identify these:
def HasAtLeastTwoBitsSet(x) :
return (x & (x-1)) != 0
# Testing:
>>> [x for x in range(33) if HasAtLeastTwoBitsSet(x)]
[3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
Next step is to extract a combination of list members identified by a combination id. This is easy, thanks to the power of list comprehensions:
def GetSublistByCombination(lst, combination_id) :
res = [x for (i,x) in enumerate(lst) if combination_id & (1 << i)]
return res
# Testing:
>>> GetSublistByCombination([0,1,2,3], 1)
[0]
>>> GetSublistByCombination([0,1,2,3], 3)
[0, 1]
>>> GetSublistByCombination([0,1,2,3], 12)
[2, 3]
>>> GetSublistByCombination([0,1,2,3], 15)
[0, 1, 2, 3]
Now let's make a generator that produces all sums, together with their string representations:
def IterAllSums(lst) :
combinations = [i for i in range(1 << len(lst)) if HasAtLeastTwoBitsSet(i)]
for comb in combinations :
sublist = GetSublistByCombination(lst, comb)
sum_str = '+'.join(map(str, sublist))
sum_val = sum(sublist)
yield (sum_str, sum_val)
And, finally, let's use it:
>>> for sum_str, sum_val in IterAllSums([1,2,3,4]) : print sum_str, sum_val
1+2 3
1+3 4
2+3 5
1+2+3 6
1+4 5
2+4 6
1+2+4 7
3+4 7
1+3+4 8
2+3+4 9
1+2+3+4 10
The code below generates all "subsets" of a given list (except the empty set), i.e. it returns a list of lists.
def all_sums(l): #assumes that l is non-empty
if len(l)==1:
return ([[l[0]]])
if len(l)==0:
return []
result = []
for i in range(0,len(l)):
result.append([l[i]])
for p in all_sums(l[i+1:]):
result.append([l[i]]+p)
return result
Now you could just write a short function doit for output also:
def doit(l):
mylist = all_sums(l)
print mylist
for i in mylist:
print str(i) + " = " + str(sum(i))
doit([1,2,3,4])
With itertools (Python >=2.6) would be:
from itertools import *
a=[1,2,3,4]
sumVal=[tuple(imap(sum,combinations(a,i))) for i in range(2,len(a)+1)]

Categories