This question already has answers here:
Why can't I iterate twice over the same iterator? How can I "reset" the iterator or reuse the data?
(5 answers)
Closed 2 months ago.
if __name__ == '__main__':
arr = map(int, input().split())
a = max([x for x in arr if x != max(arr)])
print(a)
sample input: 1 2 3 4 5
goal here is to find second greatest number
type(max(arr)) is integer,
each element type in arr when looping is integer,
so why output isnt 4? This works perfectly only when I do arr = list(arr) but I want to know why wouldnt it work without it?
map returns an iterator so it can only be consumed once. The first call to max(arr) in the first iteration already consumes it for every subsequent iteration.
If you want the second largest number, just sort the array and get the second (or second-to-last, depending on how you order). This will also give you a O(nlogn) solution instead of the (potentially) O(n^2) solution that you have attempted to write.
The problem is that arr is an iterator, and you can only go through an iterator once.
You start off with [x for x in arr...] and x gets the value 1. You then take max(arr), and that's going to see the item 2, 3, 4, 5 and then use all of them up. It will return 5, but now the iterator is empty. Your outer [...] now sees that there are no more elements to look at, and returns max(1) = 1.
This question already has answers here:
Why does this iterative list-growing code give IndexError: list assignment index out of range? How can I repeatedly add (append) elements to a list?
(9 answers)
Closed 1 year ago.
the thing that I am supposed to do is,
get 10 int
find the different value after doing %42 for those 10 input int
and what I thought is, like this
n = []
for i in range(10):
a = int(input())
n[i] = a%42
s = set(n)
print(len(s))
but it didn't work with a message of
----> 4 n[i] = a%42
IndexError: list assignment index out of range
and by googling I have solved this question by adding append.
n = []
for i in range(10):
a = int(input())
print("a",a)
b = a%42
print("b",b)
n.append(b)
s = set(n)
print(len(s))
** here is my question. why did my code didn't work? I thought my method's logic is solid. Is there some knowledge that I am missing about? **
thank you previously.
actually when you were trying first way you were using lists built-in dunder(magic method) which asks that there must be an element at that index before changing its value, meanwhile list is empty and hence it can't find an element whose value has to be chanced but append works something like this:
yourList += [newElement]
which is basically like list concatination.
Your code doesn't work because n is an empty list so it has no sense to assign a value to an index.
If you know the size of your list you can do:
# this works
n = [size]
n[0] = 1
This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 1 year ago.
I was working on a list and I noticed something.
For example, this piece of code is deleting odd numbers from a list while looping over it.
numbers=[x for x in range (100)]
for nb in numbers:
if nb%2 == 1:
del numbers[numbers.index(nb)]
When you add a counter to see the total iterations you get:
numbers=[x for x in range (100)]
counter=0
for nb in numbers:
if nb%2 == 1:
del numbers[numbers.index(nb)]
counter +=1
The result is counter = 51.
However, if you add the operator list() on the for loop:
numbers=[x for x in range (100)]
counter=0
for nb in list(numbers):
if nb%2 == 1:
del numbers[numbers.index(nb)]
counter +=1
This time the result is counter = 100.
I would like to know why and what is the role of the operator list() here.
Note: if you print numbers and list(numbers) they are identical.
Your second example makes a copy of the list. You iterate through that copy, which remains at 100 elements regardless of what you do to numbers in the meantime.
Your first example alters the list as you iterate through it, a well-documented and well-know bad idea. If you print the list and current value of nb on each iteration, you'll see how the progression works. A simplistic view is that the Python interpreter walks through the list by index (position); when you shorten the list, everything shifts down one position, but that index still increments, thus skipping over one item.
If I have a list:
list = [1, 2, 3, 4, 5]
And a for loop:
for i in range(len(list)):
if list[i] > 3:
list.clear()
list.append(1)
print(list)
Now, these are just examples to show the problem I'm experiencing and that is, I want to iterate through a list based on it's length. If I meet a certain condition, I want to modify the list. However, I then want the for loop to run based on the length of the new list. The main reason for this and why I included the list.clear(), is because if the list is completely different then the one defined, the condition that I'm checking for will also apply to every element within the list starting at list[0].
So basically, I want the for loop to run based on the length of a given List, then I want it to run again, based on the length of a new List, while checking each and every iteration of the first list and the second one and so on, until I want it to break.
Hopefully, I was clear enough with my question. I'm welcome to any suggestions that are reasonably simple since I'm a beginner. If there's anything I'm doing horribly wrong, please do point that out as well.
Thank you.
It's not recommended to modify a list as you're iterating over it.
You need a way to start the for loop over from scratch, which you can do by wrapping it inside a while loop:
flag = True
while flag:
for i in range(len(items)):
if items[i] > 3:
items.clear()
items.append(1)
# break out of the for loop and start over, because flag is still True
break
else if final_condition:
# set flag to false and break out of for loop
flag = False
break
Why don't you write it like this:
i = 0
while True:
if i < len(list):
if list[i] > 3:
list.clear()
list.append(1)
i += 1
else:
break
print(list)
Hope I understood you well.
This question already has answers here:
python: restarting a loop
(5 answers)
Closed 7 years ago.
Basically, I need a way to return control to the beginning of a for loop and actually restart the entire iteration process after taking an action if a certain condition is met.
What I'm trying to do is this:
for index, item in enumerate(list2):
if item == '||' and list2[index-1] == '||':
del list2[index]
*<some action that resarts the whole process>*
That way, if ['berry','||','||','||','pancake] is inside the list, I'll wind up with:
['berry','||','pancake'] instead.
Thanks!
I'm not sure what you mean by "restarting". Do you want to start iterating over from the beginning, or simply skip the current iteration?
If it's the latter, then for loops support continue just like while loops do:
for i in xrange(10):
if i == 5:
continue
print i
The above will print the numbers from 0 to 9, except for 5.
If you're talking about starting over from the beginning of the for loop, there's no way to do that except "manually", for example by wrapping it in a while loop:
should_restart = True
while should_restart:
should_restart = False
for i in xrange(10):
print i
if i == 5:
should_restart = True
break
The above will print the numbers from 0 to 5, then start over from 0 again, and so on indefinitely (not really a great example, I know).
while True:
for i in xrange(10):
if condition(i):
break
else:
break
That will do what you seem to want. Why you would want to do it is a different matter. Maybe you should take a look at your code and make sure you're not missing an obvious and easier way to do it.
some action that resarts the whole process
A poor way to think of an algorithm.
You're just filtering, i.e., removing duplicates.
And -- in Python -- you're happiest making copies, not trying to do del. In general, there's very little call to use del.
def unique( some_list ):
list_iter= iter(some_list)
prev= list_iter.next()
for item in list_iter:
if item != prev:
yield prev
prev= item
yield prev
list( unique( ['berry','||','||','||','pancake'] ) )
The inevitable itertools version, because it just came to me:
from itertools import groupby
def uniq(seq):
for key, items in groupby(seq):
yield key
print list(uniq(['berry','||','||','||','pancake'])) # ['berry','||', 'pancake']
# or simply:
print [key for key, items in groupby(['berry','||','||','||','pancake'])]
Continue will work for any loop.
continue works in for loops also.
>>> for i in range(3):
... print 'Before', i
... if i == 1:
... continue
... print 'After', i
...
Before 0
After 0
Before 1
# After 1 is missing
Before 2
After 2
As you can see answering your question leads to some rather convoluted code. Usually a better way can be found, which is why such constructs aren't built into the language
If you are not comfortable using itertools, consider using this loop instead. Not only is it easier to follow than your restarting for loop, it is also more efficient because it doesn't waste time rechecking items that have already been passed over.
L = ['berry','||','||','||','pancake']
idx=1
while idx<len(L):
if L[idx-1]==L[idx]:
del L[idx]
else:
idx+=1
def remove_adjacent(nums):
return [a for a,b in zip(nums, nums[1:]+[not nums[-1]]) if a != b]
example = ['berry','||','||','||','pancake']
example = remove_adjacent(example)
print example
""" Output:
['berry', '||', 'pancake']
"""
And by the way this is repeating of Remove adjacent duplicate elements from a list