Limiting size of list - python

How to ensure that a list has a certain number of elements only, and extra inputs after that are ignored?
import random
diceboard = [1,2,0,4,5,0] #for example
n=0
def roll():
dice1=random.randint(1,6)
dice2=random.randint(1,6)
dice3=random.randint(1,6)
dice4=random.randint(1,6)
dice5=random.randint(1,6)
dice6=random.randint(1,6)
return [dice1,dice2,dice3,dice4,dice5,dice6]
while diceboard.index!=0: #this basically means that per each element
that does not have a value of zero(pls correct my code)
n=n+1
newroll=roll()
newroll=newroll.split(None, n)[:n] #this limits the size of the list
print(newroll)

This is an interpretation of what I understood from your question:
https://pyfiddle.io/fiddle/0893e2af-726d-4fb3-9155-d83ecc5bbd55/
import random
diceboard = [1,2,0,4,5,0] #for example
def roll():
return list(map(
lambda x: random.randint(1,6),
range(len(diceboard))
))
n=0
#this basically means that per each element
#that does not have a value of zero(pls correct my code)
non_zero_diceboard = [d for d in diceboard if d > 0]
for i in range(len(non_zero_diceboard)):
n=n+1
newroll=roll()
newroll=newroll[:n] #this limits the size of the list
print(newroll)

Related

Need to create a function cumsum that returns the cumulative sum of a list l

Full instructions: Write a function cumsum that takes a
list l as argument and returns the cumulative sum (also known as the prefix sum) of l, which is a list, say cs of the same length as l such that each element cs[i] is equal to the sum of the first i + 1 elements of l,
I have this so far but Im not sure where Im going wrong as it keeps failing all the tests.
**Also cannot assume a certain data type in the list (can be strings, integers, etc.) How would I initialize this so it can work for any data type
My code so far:
def cumsum(l):
cs = []
total = 0
for x in range(l):
total = total + x
cs.append(total)
return cs
(Note: I cannot use any imports or extra tools, supposed to use the append function)
Does anyone know what I can do to get this to work?
Adding on to Muhammad's answer, type cast x to int
def cumsum(l):
cs = []
total = 0
for x in l:
total = total + int(x)
cs.append(total)
return cs
If you can assume that all elements are of the same type, this works for numbers and string:
def cumsum(l):
cs = []
total = None
for x in l:
if total is None:
total=x
else:
total = total + x
cs.append(total)
return cs
print(cumsum([1,2,3]))

How to call my function n times within another function

I am writing a filter function such that when I insert my wave number, which is a list of numbers, the filter_wave_num function will be executed n times to change the wave number.
However, it doesnt seem to work, it repeats the output only once, when I want it to do it n times. Will appreciate your help in this.
def filter_wave_num(wave):
new_wave = []
for i in range(len(wave)):
if i == 0:
new_wave.append(int(wave[i]*0.6 + wave[i+1]*0.2))
elif i == len(wave)-1:
new_wave.append(int(wave[i-1]*0.2 + wave[i]*0.6))
else:
new_wave.append(int(wave[i-1]*0.2 + wave[i]*0.6 + wave[i+1]*0.2))
return new_wave
def filter_wave(wave,n):
for i in range(n):
filter_wave_num(wave)
return filter_wave_num(wave)
wave = [600, 3200, 7600, 13400, 18400, 22600, 24400]
# each element inside the list has to be changed n times
The filter_wave_num function works.
If you need to use it recursively n times (each time on the result obtained the previous time) modify your second function like this:
def filter_wave(wave, n):
for _ in range(n):
wave = filter_wave_num(wave)
return wave
The function you have written creates each time a new list, but you don't return the result each iteration and it's lost.
You do call your function n times, but you are calling it with the same input so you get the same output after all iterations.
Here's what you need to do:
Notice that I changed the name of 'i' to '_', this is a convention indicates we don't need to use the value of this variable
def filter_wave(wave,n):
result = wave
for _ in range(n):
result = filter_wave_num(result)
return result
Store all the iteration results in a list and then return it:
def filter_wave(wave,n):
result = []
for i in range(n):
wave = filter_wave_num(wave)
result.append(wave)
return result

Using recursion to append to a list python

I wrote a recursive program with python2 to obtain the multiplicative persistence of numbers;which is the number of times you must multiply the digits in a number until you reach a single digit. I also want to store all the successive multiplications in the list.
import operator
def persistence(n, count = []):
n = list(str(n))
if len(n) == 1:
return len(count)
else:
n = list(map(int, n))
n = reduce(operator.mul, n)
count.append(n)
return persistence(n)
The code works for the first function call made, but instead of resetting the count list to an empty list, it retains the values of whatever previously obtained values.
For the first function call:
persistence(39)
The output is 3. Which is the expected output.
However, when another function call is made:
persistence(4)
Instead of getting output 0, it outputs 3; which is the result of the first function call.
I think the problem is the global list. I tried declaring the list inside the function, but it just kept on resetting the list to empty on every recursive call.Can anyone help?
You have hit the common 'mutable default argument' gotcha.
Fixed code:
import operator
def persistence(n, count=None):
if count is None:
count = []
n = list(str(n))
if len(n) == 1:
return len(count)
else:
n = list(map(int, n))
n = reduce(operator.mul, n)
count.append(n)
return persistence(n, count) # pass in the list
Calling:
print persistence(39)
print persistence(4)
Produces:
3
0
From here: http://docs.python-guide.org/en/latest/writing/gotchas/
You'll need to set your list inside each call if it's not already set, like this:
from functools import reduce
import operator
def persistence(n, count = None):
if count is None:
count = []
n = list(str(n))
if len(n) == 1:
return len(count)
else:
n = list(map(int, n))
n = reduce(operator.mul, n)
count.append(n)
return persistence(n, count)
Note the changed recursive call at the end.

Update list to include new elements of another list (primefactor computation)

I am calculating the prime factors for all numbers contained in a list numbers. They are returned from my helper-method primefactors_of_number as a list. I want to keep track of all of them (e.g. in a list all_factors and have them in the correct quantity).
As an example, for the input
[12,16,17]
find_all_primefactors should return
[2,2,3,2,2,17]
in any order.
The point that makes me problems is to update all_factors to contain 2 only four times.
Here is my code so far:
def find_all_primefactors(list_with_numbers):
prime_factors = []
all_factors = []
for number in list_with_numbers:
prime_factors = primefactors_of_number(number)
# missing part:
# Update all_factors in a way that it contains all elements of prime_factors at least in the same quantity
return all_factors
def primefactors_of_number(number):
'''
Returns all primefactors of the specified number as a list
'''
i=2
prime_factors=[]
while i<=number:
while number%i==0:
prime_factors.append(i)
number/=i
i+=1
return prime_factors
I think I could solve this with a lot of looping and temporary values, but I assume there is probably a more elegant solution.
Another approach would be to first compute the least common multiple of the list of numbers, and then factorize that single number:
from fractions import gcd
def find_all_primefactors(list_with_numbers):
lcm = reduce(lambda a, b: a * b / gcd(a, b), list_with_numbers)
return primefactors_of_number(lcm)
I was thinking of something like:
from collections import Counter
def find_all_primefactors(list_with_numbers):
all_factors = {}
for number in list_with_numbers:
all_factors |= Counter(primefactors_of_number(number))
return all_factors
Here's a suggestion how you could modify your first function:
def find_all_primefactors(list_with_numbers):
all_factors = []
for number in list_with_numbers:
prime_factors = primefactors_of_number(number)
for x in set(prime_factors): # loop over factors without duplicates
in_all = all_factors.count(x) # how many x are already in all_factors
in_p = prime_factors.count(x) # how many x are in prime_factors
diff = in_p - in_all
all_factors.extend([x]*diff) # extend all_factors based on difference
# note that [x]*diff is [] for diff <= 0
return all_factors
primefactors_of_number stays the same. Output for
print(find_all_primefactors([12,16,17]))
is
[2, 2, 3, 2, 2, 17]

Create a long list of random values, no duplicates

I want to create a list given two inputs, and under the condition that there cannot be any duplicates. The list should contain a random sequence of numbers. Then numbers in the list are positive integers.
Input 1: the length of the list (var samples)
Input 2: the highest number of the list (var end)
I know how to do this, but I want the list to contain a vast number of numbers, 1 million numbers, or more.
I have created 2 methods to solve this problem myself, both have their issues, on of them is slow the other produces a MemoryError.
Method 1, MemoryError:
import random
def create_lst_rand_int(end, samples):
if samples > end:
print('You cannot create this list')
else:
lst = []
lst_possible_values = range(0, end)
for item in range(0, samples):
random_choice = random.choice(lst_possible_values)
lst_possible_values.remove(random_choice)
lst.append(random_choice)
return lst
print create_lst_rand_int(1000000000000, 100000000001)
Method 2, slow:
import random
def lst_rand_int(end, samples):
lst = []
# lst cannot exist under these conditions
if samples > end:
print('List must be longer or equal to the highest value')
else:
while len(lst) < samples:
random_int = random.randint(0, end)
if not random_int in lst:
lst.append(random_int)
return lst
print lst_rand_int(1000000000000, 100000000001)
Since neither of my methods work well (method 1 does work better than method 2) I would like to know how I can create a list that meets my requirements better.
Try the solution given in the docs:
http://docs.python.org/2/library/random.html#random.sample
To choose a sample from a range of integers, use an xrange() object as an argument. This is especially fast and space efficient for sampling from a large population: sample(xrange(10000000), 60).
Or, in your case, random.sample(xrange(0,1000000000000), 100000000001)
This is still a giant data structure that may or may not fit in your memory. On my system:
>>> sys.getsizeof(1)
24
So 100000000001 samples will require 2400000000024 bytes, or roughly two terabytes. I suggest you find a way to work with smaller numbers of samples.
Try:
temp = xrange(end+1)
random.sample(temp, samples)
random.sample() does not pick any duplicates.
Since sample always returns a list, you're out of luck with such a large size. Try using a generator instead:
def rrange(min, max):
seen = set()
while len(seen) <= max - min:
n = random.randint(min, max)
if n not in seen:
seen.add(n)
yield n
This still requires memory to store seen elements, but at least not everything at once.
You could use a set instead of a list, and avoid checking for duplicates.
def lr2(end, samples):
lst = set()
# lst cannot exist under these conditions
if samples > end:
print('List must be longer or equal to the highest value')
else:
for _ in range(samples):
random_int = random.randint(0, end)
lst.add(random_int)
return lst
Since your sample size is such a large percentage of the items being sampled, a much faster approach is to shuffle the list of items and then just remove the first or last n items.
import random
def lst_rand_int(end, samples):
lst = range(0, end)
random.shuffle(lst)
return lst[0:samples]
If samples > end it will just return the whole list
If the list is too large for memory, you can break it into parts and store the parts on disc. In that case a random choice should be made to choose a section, then an item in the section and remove it for each sample required.

Categories