I've been trying to write a function that can take a different number of integer parameters and return the product of the squares of the parameters.
output should be:
multiply_squares(3,2,1)
multiply_squares(2,5)
36
100
So far I've been playing around with this:
def multiply_squares(*num_tuple):
result = []
for num in num_tuple:
c = num_tuple[num]**2
result.append(c)
for i in result:
d *= result[i]
print(d)
multiply_squares(3,2,1)
multiply_squares(2,5)
I've been getting "tuple index out of range" and haven't been able to solve this properly. Could anyone help me out? And also show me how to turn this into a recursive function?(if possible)
I got a test on Tuesday and I'm trying to understand the logic behind this :)
Any feedback/guidance is appreciated !
for num in num_tuple means iterate over num_tuple and set each value to num. num isn't the index of the tuple.
def multiply_squares(*num_tuple):
result = []
for num in num_tuple:
c = num**2
result.append(c)
d = 1
for i in result:
d *= i
print(d)
return d
multiply_squares(3,2,1)
multiply_squares(2,5)
Regarding recursive solution:
def multiply_squares(*num_tuple):
if not num_tuple: # Base case:
return 1
return (num_tuple[0] ** 2) * multiply_squares(*num_tuple[1:])
Why the need for the intermediary list?
def multiply_squares(*num_tuple):
r = 1
for n in num_tuple:
r *= n * n
return r
and it works:
>>> multiply_squares(3,2,1)
36
>>> multiply_squares(2,5)
100
Recursively:
def multiply_squares(*num_tuple):
return num_tuple[0] ** 2 * multiply_squares(*num_tuple[1:]) if num_tuple else 1
Just to help with the understanding, I'll just print the inputs to each function call:
>>> multiply_squares(3,2,1)
(3, 2, 1)
(2, 1)
(1,)
()
36
So each guy who gets called knows: its job and its inputs (the numbers). So all it needs to return (either to the initial caller (you) or the guy above him) is what the product of the squares of inputs are.
To do this, the guy can break down his problem by just multiplying the square of the first input to whatever the result of the product of the squares of the other inputs is (through recursively calling himself).
And this will work perfectly... Until, eventually, there are no other inputs. In this case, what does the guy do? Well, this is a special case which will only be instantiated by another person solving the same problem as he is. And the person above him is relying on him to return the product of the squares of that guy's remaining inputs so he can multiply his result to that result. For that reason, he must return 1 otherwise the whole system wouldn't work.
In Python we can test whether the function had no inputs by checking the truthiness of the input tuple. This just so happens to equate to checking whether that data structure has any elements.
I.e.
bool(tuple()) #empty tuple
#False
bool((1,2,3)) #populated tuple
#True
We could just as easily checked whether the length of the tuple was equal (or in this case not equal) to 0.
I.e.
len(tuple()) != 0
#False
len((1,2,3)) != 0
#True
So walking it through:
num_tuple[0] ** 2 * multiply_squares(*num_tuple[1:]) if num_tuple else 1
# ^ ^ ^ ^ ^
# 1st input sqrd | by the prod of sqrs of rest | given inputs | otherwise 1
# multiplied only if
Why doesn't your code work:
The line:
for num in num_tuple:
iterates over the elements of the num_tuple tuple, not the indicies.
This means that in the first example, num will be 3, then 2 and then 1. Then, instead of indexing the num_tuple with what you thought were the indicies (0, 1 and 2) you are instead indexing with these inputs to the function.
This results in the out of range error as you try to index the tuple with 3 when the length of the tuple is only three elements long (making [2] the last index).
To remedy your solution, you could either change that line to:
for index in range(num_tuple):
and then your indexing will work (if you also replace all previous occurrences of num with index).
Alternatively, a better solution would be to scrap the indexing altogether and just use the elements directly as that is what you want.
That would look something like:
def multiply_squares(*num_tuple):
result = []
for num in num_tuple:
c = num**2
result.append(c)
r = 1
for i in result:
r *= i
return r
which now works as expected.
Please have a look at this two-line solution (because of the assertion) using functools.reduce:
from functools import reduce
a = (3, 2, 1)
b = (2, 5)
c = 2
def multiply_squares(*nums):
assert nums # make sure we get input
return reduce(lambda x, y: x * (y**2), nums, 1)
print(multiply_squares(*a))
print(multiply_squares(*b))
print(multiply_squares(c))
print(multiply_squares())
'''Output:
36
100
4
Traceback (most recent call last):
File "test.py", line 16, in <module>
print(multiply_squares())
File "test.py", line 9, in multiply_squares
assert nums
AssertionError
'''
which is actually very robust.
Related
I am trying to count permutations of a sequence of I and O symbols, representing e.g. people entering (I for "in") and leaving (O for "out") a room. For a given n many I symbols, there should be exactly as many O symbols, giving a total length of 2*n for the sequence. Also, at any point in a valid permutation, the number of O symbols must be less than or equal to the number of I symbols (since it is not possible for someone to leave the room when it is empty).
Additionally, I have some initial prefix of I and O symbols, representing people who previously entered or left the room. The output should only count sequences starting with that prefix.
For example, for n=1 and an initial state of '', the result should be 1 since the only valid sequence is IO; for n=3 and an initial state of II, the possible permutations are
IIIOOO
IIOIOO
IIOOIO
for a result of 3. (There are five ways for three people to enter and leave the room, but the other two involve the first person leaving immediately.)
I'm guessing the simplest way to solve this is using itertools.permutations. This is my code so far:
n=int(input()) ##actual length will be 2*n
string=input()
I_COUNT=string.count("I")
O_COUNT=string.count("O")
if string[0]!="I":
sys.exit()
if O_COUNT>I_COUNT:
sys.exit()
perms = [''.join(p) for p in permutations(string)]
print(perms)
the goal is to get the permutation for whatever is left out of the string and append it to the user's input, so how can I append user's input to the remaining length of the string and get the count for permutation?
#cache
def count_permutations(ins: int, outs: int):
# ins and outs are the remaining number of ins and outs to process
assert outs >= ins
if ins == 0 :
# Can do nothing but output "outs"
return 1
elif outs == ins:
# Your next output needs to be an I else you become unbalanced
return count_permutations(ins - 1, outs)
else:
# Your. next output can either be an I or an O
return count_permutations(ins - 1, outs) + count_permutations(ins, outs - 1)
If, say you have a total of 5 Is and 5 Os, and you've already output one I, then you want: count_permutations(4, 5).
I'm guessing the simplest way to solve this is using itertools.permutations
Sadly, this will not be very helpful. The problem is that itertools.permutations does not care about the value of the elements it's permuting; it treats them as all distinct regardless. So if you have 6 input elements, and ask for length-6 permutations, you will get 720 results, even if all the inputs are the same.
itertools.combinations has the opposite issue; it doesn't distinguish any elements. When it selects some elements, it only puts those elements in the order they initially appeared. So if you have 6 input elements and ask for length-6 combinations, you will get 1 result - the original sequence.
Presumably what you wanted to do is generate all the distinct ways of arranging the Is and Os, then take out the invalid ones, then count what remains. This is possible, and the itertools library can help with the first step, but it is not straightforward.
It will be simpler to use a recursive algorithm directly. The general approach is as follows:
At any given time, we care about how many people are in the room and how many people must still enter. To handle the prefix, we simply count how many people are in the room right now, and subtract that from the total number of people in order to determine how many must still enter. I leave the input handling as an exercise.
To determine that count, we count up the ways that involve the next action being I (someone comes in), plus the ways that involve the next action being O (someone leaves).
If everyone has entered, there is only one way forward: everyone must leave, one at a time. This is a base case.
Otherwise, it is definitely possible for someone to come in. We recursively count the ways for everyone else to enter after that; in the recursive call, there is one more person in the room, and one fewer person who must still enter.
If there are still people who have to enter, and there is also someone in the room right now, then it is also possible for someone to leave first. We recursively count the ways for others to enter after that; in the recursive call, there is one fewer person in the room, and the same number who must still enter.
This translates into code fairly directly:
def ways_to_enter(currently_in, waiting):
if waiting == 0:
return 1
result = ways_to_enter(currently_in + 1, waiting - 1)
if currently_in > 0:
result += ways_to_enter(currently_in - 1, waiting)
return result
Some testing:
>>> ways_to_enter(0, 1) # n = 1, prefix = ''
1
>>> ways_to_enter(2, 1) # n = 3, prefix = 'II'; OR e.g. n = 4, prefix = 'IIOI'
3
>>> ways_to_enter(0, 3) # n = 3, prefix = ''
5
>>> ways_to_enter(0, 14) # takes less than a second on my machine
2674440
We can improve the performance for larger values by decorating the function with functools.cache (lru_cache prior to 3.9), which will memoize results of the previous recursive calls. The more purpose-built approach is to use dynamic programming techniques: in this case, we would initialize 2-dimensional storage for the results of ways_to_enter(x, y), and compute those values one at a time, in such a way that the values needed for the "recursive calls" have already been done earlier in the process.
That direct approach would look something like:
def ways_to_enter(currently_in, waiting):
# initialize storage
results = [[0] * currently_in for _ in waiting]
# We will iterate with `waiting` as the major axis.
for w, row in enumerate(results):
for c, column in enumerate(currently_in):
if w == 0:
value = 1
else:
value = results[w - 1][c + 1]
if c > 0:
value += results[w][c - 1]
results[w][c] = value
return results[-1][-1]
The product() function from itertools will allow you to generate all the possible sequences of 'I' and 'O' for a given length.
From that list, you can filter by the sequences that start with the user-supplied start_seq.
From that list, you can filter by the sequences that are valid, given your rules of the number and order of the 'I's and 'O's:
from itertools import product
def is_valid(seq):
'''Evaluates a sequence I's and O's following the rules that:
- there cannot be more outs than ins
- the ins and outs must be balanced
'''
_in, _out = 0, 0
for x in seq:
if x == 'I':
_in += 1
else:
_out += 1
if (_out > _in) or (_in > len(seq)/2):
return False
return True
# User inputs...
start_seq = 'II'
assert start_seq[0] != 'O', 'Starting sequence cannot start with an OUT.'
n = 3
total_len = n*2
assert len(start_seq) < total_len, 'Starting sequence is at least as big as total number, nothing to iterate.'
# Calculate all possible sequences that are total_len long, as tuples of 'I' and 'O'
seq_tuples = product('IO', repeat=total_len)
# Convert tuples to strings, e.g., `('I', 'O', 'I')` to `'IOI'`
sequences = [''.join(seq_tpl) for seq_tpl in seq_tuples]
# Filter for sequences that start correctly
sequences = [seq for seq in sequences if seq.startswith(start_seq)]
# Filter for valid sequences
sequences = [seq for seq in sequences if is_valid(seq)]
print(sequences)
and I get:
['IIIOOO', 'IIOIOO', 'IIOOIO']
Not very elegant perhaps but this certainly seems to fulfil the brief:
from itertools import permutations
def isvalid(start, p):
for c1, c2 in zip(start, p):
if c1 != c2:
return 0
n = 0
for c in p:
if c == 'O':
if (n := n - 1) < 0:
return 0
else:
n += 1
return 1
def calc(n, i):
s = i + 'I' * (n - i.count('I'))
s += 'O' * (n * 2 - len(s))
return sum(isvalid(i, p) for p in set(permutations(s)))
print(calc(3, 'II'))
print(calc(3, 'IO'))
print(calc(3, 'I'))
print(calc(3, ''))
Output:
3
2
5
5
def solve(string,n):
countI =string.count('I')
if countI==n:
return 1
countO=string.count('O')
if countO > countI:
return 0
k= solve(string + 'O',n)
h= solve(string + 'I',n)
return k+h
n= int(input())
string=input()
print(solve(string,n))
This is a dynamic programming problem.
Given the number of in and out operations remaining, we do one of the following:
If we're out of either ins or outs, we can only use operations of the other type. There is only one possible assignment.
If we have an equal number of ins or outs, we must use an in operation according to the constraints of the problem.
Finally, if we have more ins than outs, we can perform either operation. The answer, then, is the sum of the number of sequences if we choose to use an in operation plus the number of sequences if we choose to use an out operation.
This runs in O(n^2) time, although in practice the following code snippet can be made faster using a 2D-list rather than the cache annotation (I've used #cache in this case to make the recurrence easier to understand).
from functools import cache
#cache
def find_permutation_count(in_remaining, out_remaining):
if in_remaining == 0 or out_remaining == 0:
return 1
elif in_remaining == out_remaining:
return find_permutation_count(in_remaining - 1, out_remaining)
else:
return find_permutation_count(in_remaining - 1, out_remaining) + find_permutation_count(in_remaining, out_remaining - 1)
print(find_permutation_count(3, 3)) # prints 5
The number of such permutations of length 2n is given by the n'th Catalan number. Wikipedia gives a formula for Catalan numbers in terms of central binomial coefficients:
from math import comb
def count_permutations(n):
return comb(2*n,n) // (n+1)
for i in range(1,10):
print(i, count_permutations(i))
# 1 1
# 2 2
# 3 5
# 4 14
# 5 42
# 6 132
# 7 429
# 8 1430
# 9 4862
I simply do not understand why this is not returning the value and stopping the recursion. I have tried everything but it seems to just keep on going no matter what I do. I am trying to get the program to get the loop to compare the first two values of the list if they are the same return that it was the first value. If they were not, add the first and second values of each list and compare, etc etc until it reaches the end of the list. If the sum of the values in each list never equal each other at any point then return 0.
It is supposed to take three inputs:
A single integer defining the length of the next two inputs
First set of input data
Second set of input data
Ex input
3
1 3 3
2 2 2
It should output a single number. In the case of the example data, it should output 2 because the sum of the lists equalled at the second value.
N = int(input())
s1 = input().split()
s2 = input().split()
count = 0
def func1(x,y):
if x == y:
return(count)
elif (N - 1) == count:
return(0)
else:
count + 1
return(func1(x + int(s1[count]), y + int(s2[count])))
days = func1(int(s1[0]),int(s2[0]))
print(days)
I am sorry in advance if I really messed up the formatting or made some dumb mistake, I am pretty new to programming and I have never posted on here before. Thanks in advance :)
The problem is that you never actually update the variable count. However, just writing:
count += 1
is not going to work either without declaring the variable global:
def func1(x, y):
global count
....
That said, global variables increase code complexity and break re-enterability, i.e. the same function can no longer be called twice, not to mention about concurrency. A much cleaner way is to make count a function argument, it will look like this (the code not tested and is here for illustration only):
N = int(input())
s1 = [int(c) for c in input().split()]
s2 = [int(c) for c in input().split()]
def func1(x, y, count=0):
if x == y:
return count
elif count == N - 1:
return 0
else:
return(func1(x + s1[count], y + s2[count]), count + 1)
days = func1(int(s1[0]),int(s2[0]))
print(days)
To answer "How would you go about solving this problem then" – If I understood the problem correctly, the aim is to find the index where the "running total" of the two lists is the same. If so,
def func1(s1, s2):
total_a = 0
total_b = 0
for i, (a, b) in enumerate(zip(s1, s2)):
total_a += a
total_b += b
if total_a == total_b:
return i
return 0
print(func1([1, 3, 3], [2, 2, 2]))
does the trick. (I've elided the input bits here – this function just works with two lists of integers.)
I am curious to find out a function to check if a given list is periodic or not and return the periodic elements. lists are not loaded rather their elements are generated and added on the fly, if this note will make the algorithm easier anyhow.
For example, if the input to the function is [1,2,1,2,1,2,1,2], the output shall be (1,2).
I am looking for some tips and hints on the easier methods to achieve this.
Thanks in advance,
This problem can be solved with the Knuth-Morris-Pratt algorithm for string matching. Please get familiar with the way the fail-links are calculated before you proceed.
Lets consider the list as something like a sequence of values (like a String). Let the size of the list/sequence is n.
Then, you can:
Find the length of the longest proper prefix of your list which is also a suffix. Let the length of the longest proper prefix suffix be len.
If n is divisible by n - len, then the list is periodic and the period is of size len. In this case you can print the first len values.
More info:
GeeksForGeeks article.
Knuth-Morris-Pratt algorithm
NOTE: the original question had python and python-3.x tags, they were edited not by OP, that's why my answer is in python.
I use itertools.cycle and zip to determine if the list is k-periodic for a given k, then just iterate all possible k values (up to half the length of the list).
try this:
from itertools import cycle
def is_k_periodic(lst, k):
if len(lst) < k // 2: # we want the returned part to repaet at least twice... otherwise every list is periodic (1 period of its full self)
return False
return all(x == y for x, y in zip(lst, cycle(lst[:k])))
def is_periodic(lst):
for k in range(1, (len(lst) // 2) + 1):
if is_k_periodic(lst, k):
return tuple(lst[:k])
return None
print(is_periodic([1, 2, 1, 2, 1, 2, 1, 2]))
Output:
(1, 2)
Thank you all for answering my question. Neverthelss, I came up with an implementation that suits my needs.
I will share it here with you looking forward your inputs to optimize it for better performance.
The algorithm is:
assume the input list is periodic.
initialize a pattern list.
go over the list up to its half, for each element i in this first half:
add the element to the pattern list.
check if the pattern is matched throughout the list.
if it matches, declare success and return the pattern list.
else break and start the loop again adding the next element to the pattern list.
If a pattern list is found, check the last k elements of the list where k is len(list) - len(list) modulo the length of the pattern list, if so, return the pattern list, else declare failure.
The code in python:
def check_pattern(nums):
p = []
i = 0
pattern = True
while i < len(nums)//2:
p.append(nums[i])
for j in range(0, len(nums)-(len(nums) % len(p)), len(p)):
if nums[j:j+len(p)] != p:
pattern = False
break
else:
pattern = True
# print(nums[-(len(nums) % len(p)):], p[:(len(nums) % len(p))])
if pattern and nums[-(len(nums) % len(p)) if (len(nums) % len(p)) > 0 else -len(p):] ==\
p[:(len(nums) % len(p)) if (len(nums) % len(p)) > 0 else len(p)]:
return p
i += 1
return 0
This algorithm might be inefficient in terms of performance but it checks the list even if the last elements did not form a complete period.
Any hints or suggestions are highly appreciated.
Thanks in advance,,,
Let L the list. Classic method is: use your favorite algorithm to search the second occurence of the sublist L in the list L+L. If the list is present at index k, then the period is L[:k]:
L L
1 2 1 2 1 2 1 2 | 1 2 1 2 1 2 1 2
1 2 1 2 1 2 1 2
(This is conceptually identical to #KonstantinYovkov's answer). In Python: example with strings (because Python has no builtin sublist search method):
>>> L = "12121212"
>>> k = (L+L).find(L, 1) # skip the first occurrence
>>> L[:k]
'12'
But:
>>> L = "12121"
>>> k = (L+L).find(L, 1)
>>> L[:k] # k is None => return the whole list
'12121'
I am new to learning python. I am currently working on a problem on how to return how many eggs will fit into a carton (1 carton == a dozen eggs) and how many will be left over all based on a certain input. The challenge wants me to print the amount of cartons on one line and how many eggs left over on another.
For example:
If the input is 25, the program should print:
2
1
I am getting the right output, its just that I am having trouble outputting it like the challenge wants me to.
Basically, I created a function that does the calculations and then returns the outputs. The code is as follows.
eggs = int(input())
def dozen(x):
y = x // 12
z = x % 12
return y, z
a = dozen(eggs)
print(a)
The output I recieve on the input of 25 is:
(2, 1)
But as mentioned before, I need it to be:
2
1
I appreciate any help given. Thank you in advance!
You can index the tuple to print it separately:
print(a[0])
print(a[1])
Or, unpack the tuple and set the sep to '\n':
print(*a, sep='\n')
Or (another option!), unpack the tuple earlier:
a, b = dozen(25)
print(a)
print(b)
You can also make your code better by using divmod like so:
def dozen(x):
return divmod(x, 12)
Because integer division and modulo are essentially the same operation, it can be done in one go.
You can do any of the following:
print(*a, sep='\n') # unpack the values of and print them separated by a newline
or
a, b = dozen(eggs) # unpack the return values and assign each of them to a and b respectively
print(a, b, sep='\n')
Incidentally, the divmod builtin will just give you the correct result from the get-go.
divmod(25, 12) # returns 2, 1
eggs = int(input())
def dozen(x):
y = x // 12
z = x % 12
print(y)
print(z)
a = dozen(eggs)
why not just add the print statements to the function and lose the return.
This is merge sort tweaked to count inversions. My code throws an odd error
(I'm implementing algos to learn python 3.x).
In line 11,
in merge_sort first_sorted_half, x = merge_sort(arr[:half])
[Previous line repeated 12 more times] ValueError: not enough values
to unpack (expected 2, got 1)
Even though I explicitly return two values? I'm new to python 3 so I'd like to understand exactly what's going on here, I can't seem to find a similar issue anywhere. A link to python docs for more on this would also be appreciated!
def merge_sort(arr):
if len(arr) <= 1:
return arr
half = int(len(arr)/2)
first_sorted_half, x = merge_sort(arr[:half])
second_sorted_half, y = merge_sort(arr[half:])
merged_halves, z = merge(first_sorted_half, second_sorted_half)
return merged_halves, x + y + z
def merge(first_half, second_half):
n = len(first_half) + len(second_half)
i = 0
j = 0
split_inversions = 0
ans = []
for k in range(n):
if i >= len(first_half):
ans.append(second_half[j])
j += 1
continue
if j >= len(second_half):
ans.append(first_half[i])
i += 1
continue
if first_half[i] > second_half[j]:
ans.append(second_half[j])
j += 1
split_inversions += len(first_half) - i
elif first_half[i] < second_half[j]:
ans.append(first_half[i])
i += 1
return ans, split_inversions
numbers = [3,2,1,4,5,6,8,10,9]
print(merge_sort(numbers))
The error you are getting says that your program executed that recursive call 12 times, and at the end it couldn't unpack the result.
What that means is, python expects you to return two values from merge_sort, because you unpack the result into first_sorted_half and x. However, when you return only arr from the condition len(arr) <=1, there is no value to unpack, only there exists the array.
So how you fix that is returning a value for the base case, like return arr, len(arr).
Whilst ilke444 is right - a bit more clarification is needed. To start: returning data variables is what you need but I do not know much about the len(arr) <=1 , and I am quite new to stackflow, I do not know this feature of Python 3. I specialize in Pygame/ standard packages.
First thing - arr in this "Code Snippet" (If it is) is not defined; and/or will need to be defined. Len stands for length as you know - and uses a quote (' ') to use it.
Like so:
len('arr')
would print:
3
because there are 3 Characters in this set. You are obviously new to python 3 as you said because the syntax is slightly different.
As this probably only solves the first bit - with this info I will leave you with 1 thing more.
Call to print requires a quote (' '),
Lists have [ ] Brackets instead of (),
Dictionaries have {} brackets and variables now require definition either by variable definition or function unless put in quote marks.
Thanks,
Jerry