Recursion Question in Python. No Conditionals or Loops - python
I am trying to figure out how to print the word "hello" 121 times in python. I need to use a function without conditionals or loops, no new lines, and no multiplying the string by an integer.
I thinking something like:
print_hello():
print('hello')
print_hello()
print_hello()
but I can't seem to find a way to limit the recursive output without conditionals. Any help would be greatly appreciated.
Update
Here are all of the constraints to the challenge, it's possible recursion isn't the right approach.
max 20 lines of code
no inputs to a function.
no imports or modules
no if statements
no loops (for or while)
no new line characters (\n)
can't do something like: print("hello\n"*121)
no semi colons or tuples
can't use exec functions
(Note: I've edited the message. So see better solution at the end)
If we don't try to find a silver bullet, using a trick that would have been forgotten in the restrictions (global variables to bypass parameters interdiction, and/try to bypass if interdiction, multiplying list to bypass multiplication of string interdiction, ...), as I understand the question, it is about finding a correct splitting in functions/subfunctions to have 20 lines of code (no semicolon)
For example, if we had to print 32 hello, we could, as geeks used to reason in power of 2,
def h2():
print("hello")
print("hello")
def h4():
h2()
h2()
def h8():
h4()
h4()
def h16():
h8()
h8()
h16()
h16()
Which are 14 lines.
But the def parts complicates things, and complicates what is optimal. For example, here, since we don't use h2 elsewhere that in h4, it would be shorter to directly print hello 4 times in h4. Likewise, for h16
def h4():
print("hello")
print("hello")
print("hello")
print("hello")
def h16():
h4()
h4()
h4()
h4()
h16()
h16()
which are only 12 lines.
Now, here, number is 121. That is a specific number. Which is even the reason why I believe that this is the kind of expected solution: it is not easy to decide what intermediate function we need to create.
That would be an interesting problem per se: create a code, that optimize the number of lines needed, using this kind of subfunctions encapsulation.
But one combination that fit in 20 lines is
def h3():
print("hello")
print("hello")
print("hello")
def h7():
h3()
h3()
print("hello")
def h15():
h7()
h7()
print("hello")
def h60():
h15()
h15()
h15()
h15()
h60()
h60()
print("hello")
I know it is way less smart (and, even, "smart ass") than all the other solutions that were proposed. But I am really convinced that this is the kind of expected solution. It may seem too simple and naive. But it is not that an easy problem to decide which h?? to write (well, it is not that hard if the constraint is just "fit in 20 lines". But I would have a harder time if the constraint was "use the smallest number of lines possible")
Edit
I couldn't resist, so I wrote a code that optimize this
def size(n, l):
ml=max(k for k in l if k<=n)
nm=n//ml
r=n-nm*ml
if r==0:
return nm
else:
return nm+size(r, l)
def sizefn(l):
return sum(size(k, [x for x in l if x<k])+1 for k in l if k>1)
def totsize(n,l):
return size(n, l) + sizefn(l)
rec=1000
def compute(l, k):
global rec
if k>120: return False
sfn =sizefn(l)
if sfn+2>=rec:
return False
f = size(121, l)
if sfn+f<rec:
rec=sfn+f
print(f'{sfn+f} ({sfn}+{f}) :', l)
compute(l+[k], k+1)
compute(l, k+1)
What it does is just try all possible combinations of intermediate functions. So, that is, theoretically 2¹²⁰ combinations (all intermediate function h? may exist or not), and count how many line of code that would be, and keep the best.
Except that I do it with Branch&Bound, allowing to avoid examination of whole subsets of the set of all combination.
Result is
121 (0+121) : [1]
64 (3+61) : [1, 2]
47 (6+41) : [1, 2, 3]
40 (9+31) : [1, 2, 3, 4]
37 (12+25) : [1, 2, 3, 4, 5]
36 (15+21) : [1, 2, 3, 4, 5, 6]
35 (31+4) : [1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 39]
34 (28+6) : [1, 2, 3, 4, 5, 6, 7, 8, 9, 23]
33 (28+5) : [1, 2, 3, 4, 5, 6, 7, 8, 10, 30]
32 (28+4) : [1, 2, 3, 4, 5, 6, 7, 8, 13, 39]
31 (25+6) : [1, 2, 3, 4, 5, 6, 7, 8, 23]
30 (25+5) : [1, 2, 3, 4, 5, 6, 7, 10, 30]
29 (25+4) : [1, 2, 3, 4, 5, 6, 7, 13, 39]
28 (22+6) : [1, 2, 3, 4, 5, 6, 8, 24]
27 (22+5) : [1, 2, 3, 4, 5, 6, 10, 30]
26 (20+6) : [1, 2, 3, 4, 5, 6, 23]
25 (19+6) : [1, 2, 3, 4, 5, 8, 24]
24 (19+5) : [1, 2, 3, 4, 5, 10, 30]
23 (17+6) : [1, 2, 3, 4, 6, 24]
22 (16+6) : [1, 2, 3, 4, 8, 24]
21 (16+5) : [1, 2, 3, 5, 10, 30]
20 (14+6) : [1, 2, 3, 6, 24]
19 (13+6) : [1, 2, 4, 8, 24]
18 (12+6) : [1, 2, 6, 24]
And it ends there.
Meaning that there is no better solution that the one with h2, h6, and h24 (h1 is just print(hello))
For a total of 18 lines
Which gives
def h2():
print("hello")
print("hello")
def h6():
h2()
h2()
h2()
def h24():
h6()
h6()
h6()
h6()
h24()
h24()
h24()
h24()
h24()
print("hello")
Using lazy operators and or or, it is easy to fake a conditional in python:
def print_hello(n):
n > 0 and (print('hello') or print_hello(n - 1))
print_hello(3)
# hello
# hello
# hello
print_hello(121)
# ...
You could use a "higher-order function" such as map, filter, max, min or sorted, to apply a function repeatedly to a range.
def print_hello_map(n):
any(map(lambda _: print('hello'), range(n)))
def print_hello_filter(n):
next(filter(lambda x: print('hello') or x + 1>= n, range(n)))
def print_hello_max(n):
max(range(n), key=lambda x: bool(print('hello')))
def print_hello_sorted(n):
sorted(range(n), key=lambda x: bool(print('hello')))
If you had allowed imports from the standard library, then there would have been many alternatives to map and filter, for instance functools.reduce and itertools.repeat, but also all functions from itertools that perform any kind of looping.
from functools import reduce
def print_hello_reduce(n):
reduce(lambda acc,x: print('hello'), range(n+1))
from itertools import repeat
def f(x):
yield bool(print('hello'))
def print_hello_repeat(n):
sum(repeat(f, n))
You can use the short circuiting property of and. Zero is False, every other number is True. If the first part of the expression is false the second part isn't evaluated.
def print_hello(n=121):
print('hello', end=' ')
n and print_hello(n - 1)
print_hello()
Edit: I saw that you disqualified another answer because the function had a parameter, so here's a version that uses a global variable instead. It also fixes an off-by-one problem in the original.
n = 121
def print_hello():
global n
print('hello', end=' ')
n -= 1
n and print_hello()
print_hello()
Just using lists its pretty easy:
def myr(l=[lambda *a: 0] + 120*[lambda a, b: a(b)]):
print("hello", end="")
l.pop()(myr, l)
myr()
from sys import setrecursionlimit
setrecursionlimit(121)
def phello():
print('hello', end='')
phello()
try:
phello()
except:
print('done')
def print_hello():
print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello'); print('hello');
def print_hello(i):
print('hello', end="")
i -= 1
a = 42 / i
try:
print_hello(i)
except ZeroDivisionError:
pass
print_hello(121)
The 42 could be anything really, just need to trigger the division by 0 error
OK. Just another answer, just for fun.
def print_hello121():
print(('\n'.join(['hello']*121)))
Here - we multiply the list, not the string.
The idea.
def loop(x):
try:
next(x)
print("hello", end="")
loop(x)
except StopaIteration:
pass
def hello(n_repeat):
loop(iter(range(n_repeat)))
...
hello(50)
def print_single_hello():
print('hello')
def print_hello121():
[print_single_hello()] * 121
This does not actually works correctly, but it can be an idea.
Related
Python - Creating classes & calculation methods with dataframe inputs
I need to build classes and methods for different calculation steps: I got a dataframe with numerical columns A,B,C. I want the class to initialize the columns of the dataframe as inputs so I can call following methods: Method1: sum(A) Method2: sum(A)*B How do you do that in Python? I know it is a really general question, but I only came across really abstract OOP tutorials. I need it more specific on calculations & finance. A good source to some tutorial would also help. Thanks, KS
You can do like this. import pandas as pd import numpy as np class MyCalculator: def __init__(self, df): self.df = df def m1(self): return self.df['A'].sum() def m2(self): # return np.multiply(self.m1(), self.df['B']).values return np.multiply(self.m1(), self.df['B']).values.reshape(-1, 1) d = { 'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9] } def main(): df = pd.DataFrame(d) print(f'frame:\n {df}') b = MyCalculator(df) print(f'method 1:\n {b.m1()}') print(f'method 2:\n {b.m2()}') # start main() Output: frame: A B C 0 1 4 7 1 2 5 8 2 3 6 9 method 1: 6 method 2: [[24] [30] [36]]
change value in a column with apply lambda
Do you have a trick to avoid that the following code changes the cells (and keep the existing data) when the condition in the lambda function is not met df['test'] = df['Q8_3'].apply(lambda x: 'serial' if x >=3 else 'toto') This code is running when I add 'toto' after the else statement but I would like to bypass the else statement. Thanks for your help
is this helps you? df = pd.DataFrame({ 'Q8_3': [1, 2, 3, 4, 5], 'test': ['old','old','old','old','old'] }) df.loc[df.Q8_3 >3 , 'test'] = "serial" print(df) Output: Q8_3 test 0 1 old 1 2 old 2 3 old 3 4 serial 4 5 serial
Or even better with np.where: df['test'] = np.where(df['Q8_3'] >= 3, 'serial', df['Q8_3'])
Extract subgroups from pandas dataframe
I have the following table in a Pandas dataframe: Seconds Color Break NaN End 0.639588 123 4 NaN - 1.149597 123 1 NaN - 1.671333 123 2 NaN - 1.802052 123 2 NaN - 1.900091 123 1 NaN - 2.031240 123 4 NaN - 2.221477 123 3 NaN - 2.631840 123 2 NaN - 2.822245 123 1 NaN - 2.911147 123 4 NaN - 3.133344 123 1 NaN - 3.531246 123 1 NaN - 3.822389 123 1 NaN - 3.999389 123 2 NaN - 4.327990 123 4 NaN - I'm trying to extract subgroups of the column labelled as 'Break' in such a way that the first and last item of each group is a '4'. So, the first group should be: [4,1,2,2,1,4]; the second group: [4,3,2,1,4]; the third group: [4,1,1,1,2,4]. The last '4' of each group is the first '4' of the following group. I have the following code: groups = [] def extract_phrases_between_four(data, new_group = []): row_iterator = data.iterrows() for i, row in row_iterator: #for index, row in row_iterator if row['Break_Level_Annotation'] != '4': new_group.append(row['Break_Level_Annotation']) if row['Break_Level_Annotation'] == '4': new_group = [] new_group.append(row['Break_Level_Annotation']) groups.append(new_group) return groups but my output is: [[4,1,1,1,2],[4,1,1,1,2],[4,1,1,1,2],[4,1,1,1,2],[4,1,1,1,2],[4,3,2,1],[4,3,2,1],[4,3,2,1],[4,3,2,1],[4,1,1,1,2],[4,1,1,1,2],[4,1,1,1,2],[4,1,1,1,2]]. It's returning the same new_group repeatedly as many times as there are items in each new_group, while at the same time not including the final '4' of each new_group. I've tried to move around the code but I can't seem to understand what the problem is. How can I get each new_group to include its first and final '4' and for the new_group to be included only once in the array 'groups'?
IIUC you can extract the index and use list comprehension: s = df.loc[df["Break"].eq(4)].index print ([df.loc[np.arange(x, y+1), "Break"].tolist() for x, y in zip(s, s[1:])]) [[4, 1, 2, 2, 1, 4], [4, 3, 2, 1, 4], [4, 1, 1, 1, 2, 4]]
The problem is that in each step in the for loop, you are adding new_group to groups, although you are still adding elements to new_group. You need to execute groups.append(new_group) inside the second if statement. Also, pay attention that you can iterate directly the "Break" column values instead of the whole dataframe and accessing each time to get the value. I rewrote the code a little bit, and it looks as follows: groups = [] new_group = [] for i in data["Break"]: new_group.append(i) if i == 4: if len(new_group) > 1: groups.append(new_group) new_group = [4] print(groups) And there is the result: [[4, 1, 2, 2, 1, 4], [4, 3, 2, 1, 4], [4, 1, 1, 1, 2, 4]]
Looking for the biggest number before and after 'i' in list
I'm sorry if the title is confusing. Here's a better explanation: So basically what I need to do is iterate through every number in list and print the biggest number west (list[0:i]) and the biggest number east. If the biggest number is smaller than i, we print i. So for list [1, 3, 2, 4, 3] the output should be: 1 4 3 4 3 4 4 4 4 3 I thought my code was correct but it doesn't work for the last number in list, is anyone able to help? 'a' is the list in my code a = [1, 3, 2, 4, 3] for i in a: west = a[0:i] east = a[i:int(len(a))] if max(west) > i: print(max(west)) else: print(i) if max(east) > i: print(max(east)) else: print(i)
Try: for i in range(len(a)): print(max(a[:i+1])) print(max(a[i:])) You are not iterating over the indices in your original code; and thus the partition does not make sense.
The only mistake in your code is the for i in a loop, which loops throgh i = 1,3,2,4,3 and not i=0,1,2,3,4 The following piece of code works a=[1,3,2,4,3] for i in range(len(a)) : print max(i,max(a[:i+1])) print max(i,max(a[i:]))
this may work... not fully tested but it looks correct a = [1, 3, 2, 4, 3] for i in a[:-1]: west = a[0:i] east = a[i:int(len(a))] if max(west) > i: print(max(west)) else: print(i) if max(east) > i: print(max(east)) else: print(i) num = a[-1] west = a[0:-1] if max(west) > num: print(max(west)) else: print(str(a[-1])) print(str(a[-1])) Output: 1 4 3 4 4 4 4 3
for loop conversion from C to Python
How can I write the for loop in Python as I write it in C: for(i=0;i<10;) { if(i%2==0) i=i+3; else i++; printf("%d\n",i); } Can anyone tell me about this? I searched a lot but couldn't find it. I wrote it like this in Python: for i in range(0,10): if (i%2==0): i+=3 else: i+=1 print i Output: 3 2 5 4 7 6 9 8 11 10 Expected output: 3 4 7 8 11 Can anyone also explain the reason of this output?
To write the same loop in Python: i = 0 while i < 10: if i % 2 == 0: i += 3 else: i += 1 print i Which gives: 3 4 7 8 11 Note that, per the tutorial: The for statement in Python differs a bit from what you may be used to in C or Pascal. Rather than always iterating over an arithmetic progression of numbers (like in Pascal), or giving the user the ability to define both the iteration step and halting condition (as C), Python’s for statement iterates over the items of any sequence (a list or a string), in the order that they appear in the sequence. In a Python for loop, any changes to the loop variable (i, in this case) that occur during the loop are ignored when the loop repeats, and the next value from the object being iterated over is used. In this case, the object is a list of numbers: >>> range(10) # note that a 0 start is the default [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] Some languages call this a for each loop. See also the language reference for more details.
range(0, 10) function returns list of values from 0 to 9: range(0, 10) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] Then for body is executed for each element in this list. If You have 0, the 0 % 2 == 0 so it prints 0 + 3 etc. In C You changed i value so You jumped to other value in set. Using python's for You will get through all elements. You should use i = 0 while i < 10: if (i % 2 == 0): i += 3 else: i += 1 print i To have same results as in C
try this for i in range(10): if i%2 == 0: i = i+3 else: i = i + 1 print i it gives the same output u asked for...hope this helps