How for I get the "rest of the list" after the the current element for an iterator in a loop?
I have a list:
[ "a", "b", "c", "d" ]
They are not actually letters, they are words, but the letters are there for illustration, and there is no reason to expect the list to be small.
For each member of the list, I need to:
def f(depth, list):
for i in list:
print(f"{depth} {i}")
f(depth+1, rest_of_the_list_after_i)
f(0,[ "a", "b", "c", "d" ])
The desired output (with spaces for clarity) would be:
0 a
1 b
2 c
3 d
2 d
1 c
2 d
1 d
0 b
1 c
2 d
1 d
0 c
1 d
0 d
I explored enumerate with little luck.
The reality of the situation is that there is a yield terminating condition. But that's another matter.
I am using (and learning with) python 3.10
This is not homework. I'm 48 :)
You could also look at it like:
0 a 1 b 2 c 3 d
2 d
1 c 2 d
1 d
0 b 1 c 2 d
1 d
0 c 1 d
0 d
That illustrates the stream nature of the thing.
Seems like there are plenty of answers here, but another way to solve your given problem:
def f(depth, l):
for idx, item in enumerate(l):
step = f"{depth * ' '} {depth} {item[0]}"
print(step)
f(depth + 1, l[idx + 1:])
f(0,[ "a", "b", "c", "d" ])
def f(depth, alist):
# you dont need this if you only care about first
# for i in list:
print(f"{depth} {alist[0]}")
next_depth = depth + 1
rest_list = alist[1:]
f(next_depth,rest_list)
this doesnt seem like a very useful method though
def f(depth, alist):
# if you actually want to iterate it
for i,item in enumerate(alist):
print(f"{depth} {alist[0]}")
next_depth = depth + 1
rest_list = alist[i:]
f(next_depth,rest_list)
I guess this code is what you're looking for
def f(depth, lst):
for e,i in enumerate(lst):
print(f"{depth} {i}")
f(depth+1, lst[e+1:])
f(0,[ "a", "b", "c", "d" ])
Related
I'm trying to write a file where you have 2 rows, with the first row being numbers and the 2nd row being letters. As an example, I was trying to do this with the alphabet.
list1=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
list2=list1+list1
abcList = [[],[]]
for i in range(len(list2)):
i+=1
if i % 5 == 0:
if i>=10:
abcList[0].append(str(i) + ' ')
else:
abcList[0].append(str(i) + ' ')
elif i<=1:
abcList[0].append(str(i) + ' ')
else:
abcList[0].append(' ')
for i,v in enumerate(list2):
i+=1
if i > 10:
abcList[1].append(' '+v+' ')
else:
abcList[1].append(v+' ')
print(''.join(abcList[0]))
print(''.join(abcList[1]))
with open('file.txt','w') as file:
file.write(''.join(abcList[0]))
file.write('\n')
file.write(''.join(abcList[1]))
The problem with the above setup is its very "hacky" (I don't know if its the right word). It "works", but its really just modifying 2 lists to make sure they stack on top of one another properly. The problem is if your list becomes too long, then the text wraps around, and stacks on itself instead of the numbers. I'm looking for something a bit less "hacky" that would work for any size list (trying to do this without external libraries, so I don't want to use pandas or numpy).
Edit: The output would be:
1 5 10
A B C D E F G H I J...etc.
Edit 2:
Just thought I'd add, I've gotten this far with it so far, but I've only been able to make columns, not rows.
list1=['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
list2=list1*2
abcList = [[],[]]
for i in range(len(list2)):
i+=1
if i % 5 == 0:
if i>=5:
abcList[0].append(str(i))
elif i<=1:
abcList[0].append(str(i))
else:
abcList[0].append('')
for i,letter in enumerate(list2):
abcList[1].append(letter)
for number, letters in zip(*abcList):
print(number.ljust(5), letters)
However, this no longer has the wrapping issues, and the numbers line up with the letters perfectly. The only thing now is to get them from columns to rows.
Output of above is:
1 A
B
C
D
5 E
F
G
H
I
10 J
I mean, you could do something like this:
file_contents = """...""" # The file contents. I not the best at file manipulation
def parser(document): # This function will return a nested list
temp = str(document).split('\n')
return [[line] for line in temp] # List comprehension
parsed = parser(file_contents)
# And then do what you want with that
Your expected output is a bit inconsistent, since in the first one, you have 1, 6, 11, 16... and in the second: 1, 5, 10, 15.... So I have a couple of possible solutions:
print(''.join([' ' if n%5 else str(n+1).ljust(2) for n in range(len(list2))]))
print(''.join([c.ljust(2) for c in list2]))
Output:
1 6 11 16 21 26 31 36 41 46 51
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
print(''.join([' ' if n%5 else str(n).ljust(2) for n in range(len(list2))]))
print(''.join([c.ljust(2) for c in list2]))
Output:
0 5 10 15 20 25 30 35 40 45 50
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
print(''.join(['1 ']+[' ' if n%5 else str(n).ljust(2) for n in range(len(list2))][1:]))
print(''.join([c.ljust(2) for c in list2]))
Output:
1 5 10 15 20 25 30 35 40 45 50
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
If you are wanting to keep variable width strings aligned, you could use string formatting with a width equal to the maximum of the widths of the individual items in that position. (This example will work with more than any number of lists, by the way.)
list1 = ["", "5", "", "10", "", "4"]
list2 = ["A", "B", "C", "D", "EE", "F"]
lists = [list1, list2]
widths = [max(map(len, t)) for t in zip(*lists)]
for lst in lists:
line = " ".join("{val:{width}s}".format(val=val, width=width)
for val, width in zip(lst, widths))
print(line)
gives:
5 10 4
A B C D EE F
I'm writing a program when the user enter 'apple' at first time, it will print the day 0 and the first element in list. when the user enter 'apple' at second time, it will print the day 1 and the second element. And I want to repeat these for 30 times for 30 days.
Can someone help me with this ?
Thanks
my code:
list_1=["a", "b", "c", "d", "e", "f", "g"]
index = 6
a = 0
i = 0
while True:
a = input("Enter:")
if a == "apple":
if i < 31:
index = (index + 1) % 7
d = list_1[index]
print( "day" ,i, d )
start = input("Start: ")
current = input("Current: ")
i += 1
a += 1
my output:
Enter:apple
day 0 a
Start: 2
Current: 3
day 1 b
Start: 2
Current: 3
day 2 c
Start: 2
Current: 3
...
...
...
Expexted output:
Enter:apple
day 0 a
Start: 2
Current: 3
Enter:apple
day 1 b
Start: 2
Current: 3
...
...
...
...
Enter:apple
day 6 g
Start: 2
Current: 3
Enter:apple
day 7 a
Start: 2
Current: 3
...
...
...
...
Enter:apple
day 30 c
Start: 2
Current: 3
As #aryerez has pointed already pointed out, you're initializing the variable 'i' within the loop hence it'll always get reset to zero in each iteration.
So solution will be keep the initialization line - i = 0 before the while loop.
I do not understand why you're incrementing variable 'a' because it is your input variable.
This looks like it produces what you want. You have to move both i and index outside of the loop.
list_1=["a", "b", "c", "d", "e", "f", "g"]
i = 0
index = 6
while True:
a = input("Enter:")
if a == "apple":
a = 0
if i < 31:
index = (index + 1) % 7
d = list_1[index]
print( "day" ,i, d )
start = input("Start: ")
current = input("Current: ")
i = i + 1
a = a + 1
Here's what the loop that you posted is doing
while(true) #like saying while true is a true statement or while true==true
get user input
if input == 'apple'
then set a=0, i=0, index=6
if i < 31 #which it can't be because we just set it to 0
Do some arithmetic on index #which will always start as 6 because we just assigned it
...
increase i and a by 1 #They will be equal to 1 now
Now go through the loop again
get input
if input=='apple'
set a=0, i=0, and index=6 again
check i<31 #can't be, we just set it to 0
do arithmetic on index #which is equal to 6 again because we just set it.
...
increase a and i by 1
And your loop does this over and over
But if you first assign i and index outside the loop, then we only set them equal to 0 and 6 once.
I cannot find a solution for this very specific problem I have.
In essence, I have two lists with two elements each: [A, B] and [1,2]. I want to create a nested loop that iterates and expands on the second list and adds each element of first list after each iteration.
What I want to see in the end is this:
A B
1 A
1 B
2 A
2 B
1 1 A
1 2 A
2 1 A
2 2 A
1 1 B
1 2 B
2 1 B
2 2 B
1 1 1 A
1 1 2 A
...
My problem is that my attempt at doing this recursively splits the A and B apart so that this pattern emerges (note the different first line, too):
A
1 A
2 A
1 1 A
1 2 A
2 1 A
2 2 A
1 1 1 A
1 1 2 A
...
B
1 B
2 B
1 1 B
1 2 B
2 1 B
2 2 B
1 1 1 B
1 1 2 B
...
How do I keep A and B together?
Here is the code:
def second_list(depth):
if depth < 1:
yield ''
else:
for elements in [' 1 ', ' 2 ']:
for other_elements in list (second_list(depth-1)):
yield elements + other_elements
for first_list in [' A ', ' B ']:
for i in range(0,4):
temp=second_list(i)
for temp_list in list(temp):
print temp_list + first_list
I would try something in the following style:
l1 = ['A', 'B']
l2 = ['1', '2']
def expand(l1, l2):
nl1 = []
for e in l1:
for f in l2:
nl1.append(f+e)
yield nl1[-1]
yield from expand(nl1,l2)
for x in expand(l1, l2):
print (x)
if len(x) > 5:
break
Note: the first line of your output does not seem to be the product of the same rule, so it is not generated here, you can add it, if you want, manually.
Note2: it would be more elegant not to build the list of the newly generated elements, but then you would have to calculate them twice.
def gen():
yield '1','2',1,2
yield '1','2',1,2
yield '1','3',1,2
yield '2','4',1,2
df = pd.DataFrame(gen(), columns=["a", "b", "c", "d",]).set_index(["a", "b"])
print df # ('a','b') --> ('c','d')
We have:
c d
a b
1 2 1 2
2 1 2
3 1 2
2 4 1 2
When accessing:
print df.loc[('1','3')] # Success
print df.at[('1','3')] # KeyError: '3'
Also note, this also fails is df is a series:
print df['c'].at[('1','3')] # TypeError: _get_value() got multiple values for keyword argument 'takeable'
Is there a clear way to iterate over items for each generator in a list? I believe the simplest way to show the essence of the question is o proved an expample. Here it is
0. Assume we have an function returning generator:
def gen_fun(hint):
for i in range(1,10):
yield "%s %i" % (hint, i)
1. Clear solution with straight iteration order:
hints = ["a", "b", "c"]
for hint in hints:
for txt in gen_fun(hint):
print(txt)
This prints
a 1
a 2
a 3
...
b 1
b 2
b 3
...
2. Cumbersome solution with inverted iterating order
hints = ["a", "b", "c"]
generators = list(map(gen_fun, hints))
any = True
while any:
any = False
for g in generators:
try:
print(next(g))
any = True
except StopIteration:
pass
This prints
a 1
b 1
c 1
a 2
b 2
...
This works as expected and does what I want.
Bonus points:
The same task, but gen_fun ranges can differ, i.e
def gen_fun(hint):
if hint == 'a':
m = 5
else:
m = 10
for i in range(1,m):
yield "%s %i" % (hint, i)
The correct output for this case is:
a 1
b 1
c 1
a 2
b 2
c 2
a 3
b 3
c 3
a 4
b 4
c 4
b 5
c 5
b 6
c 6
b 7
c 7
b 8
c 8
b 9
c 9
The querstion:
Is there a way to implement case 2 cleaner?
If i understand the question correctly, you can use zip() to achieve the same thing as that whole while any loop:
hints = ["a", "b", "c"]
generators = list(map(gen_fun, hints))
for x in zip(*generators):
for txt in x:
print(txt)
output:
a 1
b 1
c 1
a 2
b 2
...
UPDATE:
If the generators are of different length, zip 'trims' them all to the shortest. you can use itertools.izip_longest (as suggested by this q/a) to achieve the opposite behaviour and continue yielding until the longest generator is exhausted. You'll need to filter out the padded values though:
hints = ["a", "b", "c"]
generators = list(map(gen_fun, hints))
for x in zip_longest(*generators):
for txt in x:
if txt:
print(txt)
You might want to look into itertools.product:
from itertools import product
# Case 1
for tup in product('abc', range(1,4)):
print('{0} {1}'.format(*tup))
print '---'
# Case 2
from itertools import product
for tup in product(range(1,4), 'abc'):
print('{1} {0}'.format(*tup))
Output:
a 1
a 2
a 3
b 1
b 2
b 3
c 1
c 2
c 3
---
a 1
b 1
c 1
a 2
b 2
c 2
a 3
b 3
c 3
Note that the different between case 1 and 2 are just the order of parameters passed into the product function and the print statement.