This question already has answers here:
recursively implementing 'minimum number of coins' in python
(6 answers)
Closed 7 years ago.
I was given a set of problems by my instructor to get us thinking about recursion. In one of them, we are given a value (the cost of postage) and a list of available denominations of stamps. The exercise involves writing a recursive function that returns a minimum length list of stamps whose total is equal to the value sum of postage.
Is the correct way to solve this just to have the a program that compares every single possibility and return the one with the smallest length? If that's the case I'm not exactly sure how to write a program for it, much less one that utilizes recursion as I am new to both python and programming in general. Based on the hints the instructor provided I came up with something like this:
stampList=[1,4,7]
postage=10
def pickStamps(postage):
if postage==0: #base case 1
return ""
if postage<0: #base case 2
return none
else:
x=postage
for i in range(len(stampList)-1):
x=x-stampList[i]
return pickStamps(x)
I was attempting to have python start with the value of postage and subtract each denomination in combination to get to zero,but I'm not sure how to make each possibility into a list. It was suggested in the problem that it might be wise to write another function that takes a parameter that is a list of lists and returns the index of the minimum length element in that list, but I'm not sure how to implement that. Can someone either show me how to write such a code or explain the best way to approach such a problem? Thanks!
def ways(wallet, stamp_values, postage):
amount = sum(wallet)
if amount == postage:
return [wallet]
elif amount > postage:
return []
else:
next_stamp = wallet[-1] if wallet else max(stamp_values)
new_stamps = stamp_values[stamp_values.index(next_stamp):]
gen = (ways(wallet + [c], new_stamps, postage=postage) for c in new_stamps)
return sum(gen, [])
Test drive:
>>> combos = ways([], stamp_values=(7,4,1), postage=10)
>>> combos
[[7, 1, 1, 1],
[4, 4, 1, 1],
[4, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
>>> min(combos, key=len)
[7, 1, 1, 1]
Note the solution is actually non-unique in your example, i.e. 7,1,1,1 and 4,4,1,1 are both the same length.
Let's imagine we have a new stamp of value 3, we should expect to see a unique solution then (7 + 3 == 10 with two stamps).
>>> ways([], stamp_values=(7,4,3,1), postage=10)
[[7, 3],
[7, 1, 1, 1],
[4, 4, 1, 1],
[4, 3, 3],
[4, 3, 1, 1, 1],
[4, 1, 1, 1, 1, 1, 1],
[3, 3, 3, 1],
[3, 3, 1, 1, 1, 1],
[3, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
Imagine you have a function which already works:
def pick_stamps(postage):
'''Returns list of stamps needed to cover postage'''
Given you have this function, you can use it to implement your version:
def my_pick_stamps(postage):
if postage == 0:
return []
else:
stamp = max(stamp for stamp in stamps
if stamp <= postage)
return [stamp] + pick_stamps(postage - stamp)
Of course, once you've implemented your version you can use that instead and replace pick_stamps in your implementation with my_pick_stamps.
Related
I need to clear up missing data which are denoted by -99. If my function detects a missing data, it has to replace the missing data with the average of the values adjacent to it. However, if an average cannot be calculated because of consecutive missing data, then the missing data would have to be replaced by the immediate adjacent values. I tried to write a code for the replacement but it doesn't seem to be working. Did i do something wrong at the 'if' part? I can't use pandas or numpy so only the basic python functions are allowed.
def cleanup(data):
missing_value = -99
for num in range(len(data)):
if num == missing_value:
data[num] = (data[num-1] + data[num+1])/2
return data
data = [[1, 2, -99, 4, 5], [1, 2, -99, -99, 5],[1, 2, 3, -99, -99]]
cleanup(data)
expected output
[[1, 2, 3, 4, 5], [1, 2, 2, 5, 5], [1, 2, 3, 3, 3]]
Your data parameter is a list of lists so you will need to use a nested loop to process each sub-list independently.
For each of the sub-lists, you can use zip to obtain the previous, current and next values in one expression. applying enumerate on that will also give you the indexes.
Given that you will potentially need to propagate values over more than one position, using a propValue variable to track the propagation value will make it easier to manage. You can initialize that with the first non-missing value in the sub-list.
With the previous (P), current (V) and next (N) values, it is then only a matter of checking the condition for replacement of the missing value at the current index (i). You also need to update the propagation value as you encounter non-missing values in the sub-list.
def cleanup(values,missing=-99):
for values in data: # loop through list of lists
propValue = next(v for v in values if v is not missing) # 1st non-missing
for i,(P,V,N) in enumerate(zip([missing]+values,values,values[1:]+[missing])):
if V is not missing: propValue = V # skip non-missing values
elif N is missing: values[i] = propValue # propagate forward
elif P is missing: values[i] = N # propagate backward
else: values[i] = (P+N)//2 # use average when both present
Output:
data = [[1, 2, -99, 4, 5], [1, 2, -99, -99, 5], [1, 2, 3, -99, -99],
[1, -99, -99, -99, 5], [-99, -99, 3, 4, 5] ]
cleanup(data)
print(data)
[[1, 2, 3, 4, 5], [1, 2, 2, 5, 5], [1, 2, 3, 3, 3],
[1, 1, 1, 5, 5], [3, 3, 3, 4, 5]]
You wrote your function to deal with a list of integers, but then you gave it a list of lists. Look at the loop structure:
for num in range(len(data)):
if num == missing_value:
num is an integer subscript; in this case it iterates over the values 0, 1, 2.
This will never be equal to -99.
You have to change this to work with the lists within the input argument, and then to run through the values in each list:
for sub_list in data:
for idx in rang(sub_list):
if sub_list[idx] == missing_value:
Can you take it from there?
Please note that you should now learn basic debugging. If nothing else, learn to place strategic print commands to show the values you're using. Had you done this with your posted program, you would have seen the values you were comparing.
I think Alain's answer is probably the one you want, but I'll also list the version I put together which differs slightly in the following ways:
It handles ranges of missing values > 2 differently, whereas the previous answer propagates the value forward, this one averages the middle value, so that the average of all the values is unaffected.
This one doesn't modify the input, your original returned a modified input so the two answers here have gone in the different directions one not bothering to return the value you already have, and this one returnig you a new list of lists.
The average is floored division in the other answer whereas this one returns the mean, so if your expected result for the first missing item is 3 then you probabaly do want to use // instead of the / oepration here.
Alain's answer is also a lot pretty than mine! This one is a lot more primitive, but perhaps it is still interesting as an alternative approach.
def cleanup_series(data,missing=-99):
c = []
p = next(v for v in data if v != missing)
if len(data):
st = -1
for n in range(len(data)):
if data[n] == missing:
if st == -1:
st = n
nd = n
else:
if st > -1:
r = (1+nd-st)//2
c.extend([p]*r)
if (nd-st)%2==0:
c.append((p+data[n])/2);
c.extend([data[n]]*r)
st = -1
c.append(data[n])
p = data[n]
n += 1
if st > -1:
c.extend([p]*(1+nd-st))
return c
def cleanup(data):
return list(map(cleanup_series, data))
data = [[1, 2, -99, 4, 5], [1, 2, -99, -99, 5],[1, 2, 3, -99, -99],[1, 2, -99, -99, -99, 4, 5],[-99,-99,2]]
print(data)
print(cleanup(data))
I'm trying to understand what I'm missing in these two different methods. In the code below, I'm defining a list of lists, and calling it two ways. The first way is to call it in a print statement as one line, separating the index positions of the lists with commas, the second is to print them all separately.
list_of_lists = [[2, 2, 0], [2, 1, 0], [2, 1, 1]]
print(list_of_lists[0][0],[1][0],[2][0])
print('\n')
The output of this code is 2,1,2
print(winner_is_2[0][0])
print(winner_is_2[1][0])
print(winner_is_2[2][0])
The output of this code is 2,2,2
Why, in the first case, does the call output the wrong value for the second set of index positions?
The use case here is trying to check if a set of index positions in a list of lists is all equal to the same value (like you'd see in tic-tac-toe where you'd check if all the values in row x or column y are the same)
NOTE: I know I can use list extraction to get all the values at X position in these sublists, but I'd rather not use that method if possible.
In this snippet here:
list_of_lists = [[2, 2, 0], [2, 1, 0], [2, 1, 1]]
print(list_of_lists[0][0],[1][0],[2][0])
print('\n')
This is actually equivalent to:
list_of_lists = [[2, 2, 0], [2, 1, 0], [2, 1, 1]]
print(list_of_lists[0][0])
print([1][0])
print([2][0])
Python is interpreting the comma separated inputs as separate arrays [1] and [2] indexed by their first value [1][0] and [2][0] which leads to them being printed as 1,2
To see further evidence of this, try changing the values of 1 and 2 and seeing what you get by doing:
list_of_lists = [[2, 2, 0], [2, 1, 0], [2, 1, 1]]
print(list_of_lists[0][0],[5555][0],[262626][0])
print('\n')
Here you should get (2, 5555, 262626)
list_of_lists = [[2, 2, 0], [2, 1, 0], [2, 1, 1]]
print(list_of_lists[0][0], list_of_lists[1][0], list_of_lists[2][0])
print('\n')
Whats wrong with this?
What you trying is equivalent to:
print(list_of_lists[0][0], 1, 2)
So after a little more digging, thanks to Spencer Bard for explaining the syntax mistake, I was able to come up with code that works for precisely what I was trying to do. As I'm attempting to test a marker against each item at specific index positions within a list, the code that worked for me was as follows.
def win_check(marker_list,mark):
if (marker_list[0][0] == mark and marker_list[1][0] == mark and marker_list[2][0] == mark):
print(f'Winner is player {mark}!')
There are a lot more elif statements underneath that to account for the rest of the possibilities, but this is the general format.
The job is to return a list back as a unique list. However my code doesn't work correctly.
def unique_list(lst):
d=(lst)
print(d)
When I enter unique_list([1,1,1,1,2,2,3,3,3,3,4,5]), it returns the same thing. But when I do print(d) on a new cell, it returns the unique numbers. I'm just confused why.
Pretty sure this is what you are looking for:
example = [1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 5]
def unique_list(list_):
return list(set(list_))
print(unique_list(example))
I have a numpy array with numbers, and I want to count how many elements are equal starting from the last element.
A = [1, 3, 2, 2, 0, 3, 2, 2, 2, 2]
then I want the return value to be 4 (last four elements are equal)
print(np.argmax(A[::-1] != A[-1]))
I'm not sure about how this performs when A is super large. In that case, simple for loop would be better.
Note : Why this works can be understood with the following line in the documentation:
In case of multiple occurrences of the maximum values, the indices corresponding to the first occurrence are returned.
Thanks YSelf for correction.
For large arrays where you expect only a few items to be identical, a generator expression with next may be efficient:
A = np.array([1, 3, 2, 2, 0, 3, 2, 2, 2, 2])
last = A[-1]
res = next(i for i, j in enumerate(A[::-1]) if j != last)
# 4
I have the following list of integers:
[[0, 2, 3, 1, 3, 2, 0, 1],
[0, 3, 2, 1, 2, 3, 0, 1],
[1, 2, 3, 0, 3, 2, 1, 0],
[2, 1, 3, 0, 3, 1, 2, 0]]
Taking this whole list as a population and each sublist inside as an individual, like this example:
Population scheme
I need to create a function that will read the individuals and randomly mutate one of the chromosomes with a certain probability, taking into consideration that the numbers in the list can be only in this 0-3 range.
Would anyone know any method, or whatever approach to start developing this? I am completely lost and don't know where to begin, everything I tried has failed, so I am looking for suggestion how would one do it.
from random import randint, uniform;
def mutateIndividual(ind):
if uniform(0,1) < prob: # random probability of mutation
mutationIndex = randint(0, len(ind)) # select one chromosome
ind[mutationIndex] = randint(0,3) # mutate
return ind;
for i in range(0, len(population)): # outer loop on each individual
population[i] = mutateIndividual(population[i]);
Exercise: You may want to modify the program to mutate a chromosome to something different than what it already is.