python continuing a loop from a specific index - python

I wrote some code that uses enumerate to loop through a list.
for index, item in enumerate(list[start_idx:end_idx])
print('index [%d] item [%s]'%(str(index), item))
the item in the list are just strings. Sometimes I do not want to enumerate for the whole list, sometimes I'll slice up the list do do different things.
The part that I am having trouble with is python's enumerate function.
The docs say you can do:
for index, item in enumerate(list, start_index):
print(str(index))
the above code doesn't do what I expected. I though enumerate would start at the start position and stop at the end, but it doesn't.
I wrote a small program and it does indeed act wonky.
>>> for i, x in enumerate(range(0,20),start=4):
... print(str(i)+'\t'+str(x))
...
4 0
5 1
6 2
7 3
8 4
9 5
10 6
11 7
12 8
13 9
14 10
15 11
16 12
17 13
18 14
19 15
20 16
21 17
22 18
23 19
I would expect enumerate to start at index 4 and loop to the end. So it would get the range of 4-19 but it seems to just start the index but still iterates from 0-19..
Question, is there a way to do a iteration loop starting at a specific index in python?
My expected outcome would be
>>> for i, x in enumerate(range(0,20),start=4):
... print(str(i)+'\t'+str(x))
...
4 0 # skip
5 1 # until
6 2 # this
7 3 # item
8 4
9 5
10 6
11 7
12 8
13 9
14 10
15 11
16 12
17 13
18 14
19 15
20 16
21 17
22 18
23 19
instead of starting the index at the start position provide.

Actually if you got range object it's not a big deal to make a slice from it, because range(n)[:4] is still range object(as #MosesKoledoye mentioned it's Python 3 feature). But if you got a list, for the sake of not creating new list you can choose itertools.islice, it will return iterator.
from itertools import islice
for index, item in enumerate(islice(range(20), 4, None)):
print(index, item)
Output
0 4
1 5
2 6
3 7
4 8
...

The start parameter of enumerate doesn't have anything to do with what elements of the iterable get selected. It just tells enumerate what number to start with.
>>> list(enumerate(range(3)))
[(0, 0), (1, 1), (2, 2)]
>>> list(enumerate(range(3), 1))
[(1, 0), (2, 1), (3, 2)]
If you want to start at a specific index, you need to provide the start argument and a slice:
for i, v in enumerate(alist[4:], 4):
...

You can do:
for index, item in enumerate(list[4:]):
print(str(index))

Related

For loop runs and perform task on only the first element of the the iterable but not the rest and returns the result of only the action on 1st element

The last for loop of the code seems to only run for the first element of the list and not the rest of the element
a = int(input())
setA = set(map(int, input().split()))
n = int(input())
com = [input() for alnum in range(n*2)]
nestcom = []
cmd = []
for i in com:
if com.index(i)%2 == 0:
nestcom.append([i, com[com.index(i)+1]])
else:
continue
for x in nestcom:
y, z = x[0].split(), set(map(int, x[1].split()))
cmd.append([y, z])
for u in cmd:
eval('setA.'+cmd[0][0][0]+'('+str(cmd[0][1])+')')
print(sum(setA))
These are the inputs
16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 24 52
4
intersection_update 10
2 3 5 6 8 9 1 4 7 11
update 2
55 66
symmetric_difference_update 5
22 7 35 62 58
difference_update 7
11 22 35 55 58 62 66
I tried running code with python 3 and pypy 3 but same problem. I changed the eval() to exec() but problem still persist
here is your last loop:
for u in cmd:
eval('setA.'+cmd[0][0][0]+'('+str(cmd[0][1])+')')
You are using cmd in what you are doing within the loop, not u. That is, you aren't using each element in cmd, you are just using cmd a number of times.
You likely want to use u in the loop itself (like eval('setA.'+u[0]...)), or perhaps enumerate(cmd) to get each element and a counter and use the counter itself, like for i, u in enumerate(cmd): eval('setA.'+cmd[i][0][0]...)

How to structure nested for loops?

I am new to Python. I have been studying for loops but I can't seem to get my head around NESTED for loops. I am doing a problem which requires knowledge of nested for loops, which I do not know how to do!
Problem:
Write a for loop that produces the following output:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
0
2
4
6
8
10
12
14
16
18
0
3
6
9
12
15
18
0
4
8
12
16
Caveat: You can only use up to two for loops
My Code:
c = 0
for i in range(1, 5):
for j in range(10):
print(i * c)
c = c + 1
Any help will be appreciated. I just cannot get my head around nested for loops. It would be great if anybody could guide me.
One could do it like:
for step in range(1, 5):
for i in range(0, 20, step):
print(i)
Using list comprehension:
print(*[i for step in range(1, 5) for i in range(0, 20, step)], sep="\n")
You don't need the c variable, you can multiply by j.
The inner loop shouldn't go up to 10 every time. Notice that as the multiplyer increases, the number of iterations goes down -- each time stops before 20. So you need to divide 20 by i to get the number of iterations.
for i in range(1, 5):
for j in range(20//i):
print(i * j)

Is there a way to revert changes made to an element in a list?

I recently got help with fixing a function that changes elements in a list when printing said list. However, my program demands me being able to revert whatever changes I've made to an element in the list. Judging from the code, this should be doable with what I have, but it seems I can't alter the list once it has been altered once. The affected code looks like this:
def seatingmap():
# The parameters of seating-plan
rows = 6
seats = 4
seat_rows = [i for i in range(1, rows * seats + 1)]
seat_rows = [seat_rows[i:i + seats] for i in range(0, len(seat_rows), seats)]
return seat_rows
def find_in2Dlist(lst, item):
for index, sublist in enumerate(lst):
try:
aname = sublist.index(item)
return [index, aname]
except:
continue
return None
def printList(mlist, chosenseat):
i = 0
temp = mlist.copy()
while i < len(chosenseat):
findseat = find_in2Dlist(mlist, chosenseat[i])
if findseat == None:
i += 1
else:
temp[findseat[0]][findseat[1]] = '*' + str(temp[findseat[0]][findseat[1]]) + '*'
i += 1
for idx, row in enumerate(temp):
if idx == len(temp) // 2:
print("{:^{}}".format('↓ TYST AVD ↓', (len(row) * 4) - 2))
if idx % 2 == 1:
row = row[::-1]
print(("{:<4}" * len(row)).format(*row))
list = seatingmap()
number = [2]
printList(list, number)
number = [2,4]
printList(list, number)
Edit
If I for example run the code above, it changes this:
1 2 3 4
8 7 6 5
9 10 11 12
↓ TYST AVD ↓
16 15 14 13
17 18 19 20
24 23 22 21
To this:
1 *2* 3 *4*
8 7 6 5
9 10 11 12
↓ TYST AVD ↓
16 15 14 13
17 18 19 20
24 23 22 21
Which is good. Although, now I want be able to change it back to let's say:
1 2 3 *4*
8 7 6 5
9 10 11 12
↓ TYST AVD ↓
16 15 14 13
17 18 19 20
24 23 22 21
By removing the "2" from "chosenseats". This is where I'm stuck, as when I attempt to do this, it prints out the same list as before the 2 was removed.Is there any way I can go about this issue?
It could be fixed by simply refreshing the list each time you call printList or copying the list contents not the list, I feel that is an incomplete answer.
As far as I can see the below achieves the same result with a lot less code. It could be shortened more using list comprehensions etc. but I'm focussing here on removing unnecessary functions rather than just reducing the number of lines of code.
def generate_seatmap(rows = 6, seats_per_row = 4):
seatmap = []
for row in range(0,rows):
start_of_row = row*seats_per_row+1
seatmap.append([seat for seat in range(start_of_row,start_of_row+seats_per_row)])
return seatmap
def print_seatmap(seatmap,chosenseats=[]):
for row in seatmap:
if seatmap.index(row)%2: #reverse odd numbered rows
row.reverse()
for seat in row:
#add asterisks for seats we have chosen
printable_seat = '*'+str(seat)+'*' if seat in chosenseats else str(seat)
#add fewer spaces the longer our seat label now is up to a max of 4
print(printable_seat, end = ' '*(4-len(printable_seat)))
print("")
print_seatmap(generate_seatmap(),[1,2,24,23])

Python 2.7 list comprehension number pyramid

I am trying to create the following number pyramid using nested list comprehension and string formatting.
1
2 4
3 6 9
4 8 12 16
5 10 15 20 25
6 12 18 24 30 36
7 14 21 28 35 40 47
I figured out how to create the pyramid using nested for loops but can't quite get it to work using list comprehension. Here is my code:
for n in range(1,8):
print
for x in range(n):
if x>0:
print '%2d' % (n+(n*x)),
else:
print '%d' % n,
The same code using list comprehension gives me a syntax error:
rows = [
'%2d' % (n+(n*x)), if x > 0 else '%d' % n,
for n in range(1,8)
for x in range(n)
]
print '\n' +'\n'.join(rows)
Any ideas on how to format the pyramid correctly using list comprehension?
You could use range to build up each nested list, like so:
# Generation
result = [range(x, x**2 + 1, x) for x in range(1, 8)]
# Formatting
print('\n'.join(''.join(str(x).ljust(4) for x in row) for row in result))
Output:
1
2 4
3 6 9
4 8 12 16
5 10 15 20 25
6 12 18 24 30 36
7 14 21 28 35 42 49
You can join a list of lists (in this case, a generator of generators) by newlines
print('\n'.join(' '.join(str(i*j) for j in range(1, i+1)) for i in range(1, n+1)))
#1
#2 4
#3 6 9
#4 8 12 16
#5 10 15 20 25
#6 12 18 24 30 36
#7 14 21 28 35 42 49
and if you want to have the list that creates it just do:
rows = [[i*j for j in range(1, i+1)] for i in range(1, n+1)]

How to Align Unicode-Type Values of a Column?

I have the following output containing two columns (line# and ID):
1 Q50331
2 P75247
3 P75544
4 P22446
5 P78027
6 P75271
7 P75176
8 P0ABB4
9 P63284
10 P0A6M8
11 P0AES4
12 P39452
13 P0A8T7
14 P0A698
How can I make the ID values of second column align at the top of each other, like the following:
1 Q50331
2 P75247
3 P75544
4 P22446
5 P78027
6 P75271
7 P75176
8 P0ABB4
9 P63284
10 P0A6M8
11 P0AES4
12 P39452
13 P0A8T7
14 P0A698
The problem I am facing is how to incorporate the solution to my code. I tried to use python tabulate, but found this is not working properly since what I am printing: row[0] is a unicode from the tuple row (See the following code).
count = 0
for row in c:
count += 1
print count, row[0]
Any idea how can I incorporate tabulate or other methods to align the unicode-type values in the column?
Use alignment specifiers:
data = {
1:'Q50331',
2:'P75247',
3:'P75544',
4:'P22446',
5:'P78027',
6:'P75271',
7:'P75176',
8:'P0ABB4',
9:'P63284',
10:'P0A6M8',
11:'P0AES4',
12:'P39452',
13:'P0A8T7',
14:'P0A698',
333:'P00bar'
}
length = len(str(max(data.keys())))+1
for k,v in data.items():
print "{:<{}}{}".format(k, length, v)
Output:
1 Q50331
2 P75247
3 P75544
4 P22446
5 P78027
6 P75271
7 P75176
8 P0ABB4
9 P63284
10 P0A6M8
11 P0AES4
12 P39452
13 P0A8T7
14 P0A698
333 P00bar
I've created length which will contain the length of the max value from data keys, +1. Then I pass that length value to my alignment specifier, which in this case is 4:
{:<4}{}

Categories