This question already has answers here:
Why does len() not support iterators?
(2 answers)
Closed 7 months ago.
Getting the length of reversed list doesn't work:
lst = [1,2,3]
lst = reversed(lst)
print len(lst)
throws TypeError: object of type 'listreverseiterator' has no len()
A work around is:
lst = [1,2,3]
lst_length = len(lst)
lst = reversed(lst)
print lst_length
# OR
lst = lst[::-1]
print len(lst)
Now my real question is why?
Simply reversing a list does not alter the length of the list,
so why is Python throwing that exception?
The function reversed() returns an iterator, not an actual list.
You cannot directly get the len() of an iterator (see here).
You could instead reverse the list using Extended Slice syntax:
lst_reversed = lst[::-1]
or reverse the list in place:
lst.reverse()
If you must use an iterator you could first turn it into a list:
lst_reversed = list(reversed(lst))
With each of these approaches len() will then work as expected.
reversed doesn't produce new list, it just return iterator object. You can use lst.reverse() - and it doesn't return anything, but make your lst in reversed order
reversed returns iterator so to determine length you have to consume it.
For example rev_len = len(list(reversed(lst))).
FYI list.reverse method reverses a list in place: lst.reverse()
Anyway your reversed list has the same size as the original one, so you can just determine the length even before reversing.
Related
I'm trying to write a program that removes duplicates from a list, but my program keeps throwing the error "list index out of range" on line 5, if n/(sequence[k]) == 1:. I can't figure this out. Am I right in thinking that the possible values of "k" are 0, 1, and 2? How is "sequence" with any of those as the index outside of the possible index range?
def remove_duplicates(sequence):
new_list = sequence
for n in sequence:
for k in range(len(sequence)):
if n/(sequence[k]) == 1:
new_list.remove(sequence[k])
print new_list
remove_duplicates([1,2,3])
I strongly suggest Akavall's answer:
list(set(your_list))
As to why you get out of range errors: Python passes by reference, that is sequence and new_list still point at the same memory location. Changing new_list also changes sequence.
And finally, you are comparing items with themselves, and then remove them. So basically even if you used a copy of sequence, like:
new_list = list(sequence)
or
new_list = sequence[:]
It would return an empty list.
Your error is concurrent modification of the list:
for k in range(len(sequence)):
if n/(sequence[k]) == 1:
new_list.remove(sequence[k])
It may seem removing from new_list shouldn't effect sequence, but you did new_list = sequence at the beginning of the function. This means new_list actually literally is sequence, perhaps what you meant is new_list=list(sequence), to copy the list?
If you accept that they are the same list, the error is obvious. When you remove items, the length, and the indexes change.
P.S. As mentioned in a comment by #Akavall, all you need is:
sequence=list(set(sequence))
To make sequence contain no dupes. Another option, if you need to preserve ordering, is:
from collections import OrderedDict
sequence=list(OrderedDict.fromkeys(sequence))
If you don't like list(set(your_list)) because it's not guaranteed to preserved order, you could grab the OrderedSet recipe and then do:
from ordered_set import OrderedSet
foo = list("face a dead cabbage")
print foo
print list(set(foo)) # Order might change
print list(OrderedSet(foo)) # Order preserved
# like #Akavall suggested
def remove_duplicates(sequence):
# returns unsorted unique list
return list(set(sequence))
# create a list, if ele from input not in that list, append.
def remove_duplicates(sequence):
lst = []
for i in sequence:
if i not in lst:
lst.append(i)
# returns unsorted unique list
return lst
Playing around with python3 REPL and noticed the following:
Why are print( [zip([1,2,3], [3,1,4])] ) and print( list(zip([1,2,3], [3,1,4])) ) different?
The first returns [<zip object at 0xblah>] and the second returns [(1,3), (2,1), (3,4)].
Trying to understand why the list comprehension in the first statement doesn’t give me the result that the list() constructor gives - I think I'm confused about the difference between list comprehension and list() and would appreciate insight into what's happening under the hood.
Searching gives me this question on lists and tuples which doesn't answer my question.
Edit: A suggested question on The zip() function in Python 3 is very helpful background, but does not address the confusion in my question about the difference between a list comprehension and a list literal, so i prefer the submitted answer below as more complete.
The first statement is not a list comprehension, a list comprehension would give you the same result. It is just a list literal containing a zip object:
This would be a list comprehension:
[value for value in zip([1,2,3], [3,1,4])]
The above will print the same as list(zip([1, 2, 3], [3, 1, 4])).
In general, [something] means: A list with one element: something.
On the other hand, list(something) means: Iterate over the values in something, and make a list from the result. You can see the difference for example by putting primitive objects inside it, like a number:
>>> [2]
[2]
>>> list(2)
TypeError: 'int' object is not iterable
Let's say I have a list of unknown size, then I can access the last element using:
>>> l = list(range(10))
>>> l[-1]
9
However, is there any way to do this via a slice object like
>>> s = slice(-1, 10)
>>> l[s]
[9]
without knowing the length of my list?
Edit:
I simplified my Question a bit. I am fine with getting a list back, since I am iterating over the sublist later. I just needed a way of getting the last item of list besides being able to get every second element and so on ...
Yes, just use None as the end argument:
In [53]: l[slice(-1, None)]
Out[53]: [9]
This will of course produce a list [9], rather than the 9 in your question, because slicing a list always produces a sublist rather than a bare element.
If your objective is to pass arguments which you can use to index a list, you can use operator.itemgetter:
from operator import itemgetter
L = range(10)
itemgetter(-1)(L) # 9
In my opinion, for this specific task, itemgetter is cleaner than extracting a list via a slice, then extracting the only element of the list.
Note also that this works on a wider range of objects than just lists, e.g. with range as above.
If you were to access the last element of the list:
n = int(input())
user_input = [int(input) for i in range(n)]
last_element = user_input[-1]
Here we have used negative indices concept in lists.
This question already has answers here:
Why do these list operations (methods: clear / extend / reverse / append / sort / remove) return None, rather than the resulting list?
(6 answers)
Closed 6 years ago.
I wrote a very basic python code, but it didn't work:
str = "asddasdvsatvsyvcstvcsacvsacvsaifteiopvnvbcshavsdsdzasbbnyju"
dict = {}
for i in str:
dict[i] = dict.get(i,0)+1
print(list(dict.items()).sort())
then I just changed the sequence of functions and separated them, and surprisingly it worked!
str = "asddasdvsatvsyvcstvcsacvsacvsaifteiopvnvbcshavsdsdzasbbnyju"
dict = {}
for i in str:
dict[i] = dict.get(i,0)+1
mylist = list(dict.items())
mylist.sort()
print(mylist)
What's happened from my first to second code that makes it work?
list.sort() sorts the list in place but returns None, that's why in the first example you're seeing None printed out.
You could use built-in sorted, that works exactly the same but creates and returns new list.
sort returns nothing. Therefore, print(l.sort()) prints nothing.
However, l.sort(), and therefore print(l.sort()), does sort the l
list.
Therefore, printing l after l.sort() has been executed will print something, namely, the l list sorted.
.sort() sorts the list in-place (it changes the list itself and doesn't make a copy). But it doesn't return anything (other than None).
If you do
print(list(dict.items()).sort())
You print the return value of sort() -- which is None.
But with
mylist.sort()
print(mylist)
You first sort, and then you print the value of mylist. That's what you want.
You could also have done
print(sorted(mylist))
But that leaves mylist unchanged.
I'm trying to write a program that removes duplicates from a list, but my program keeps throwing the error "list index out of range" on line 5, if n/(sequence[k]) == 1:. I can't figure this out. Am I right in thinking that the possible values of "k" are 0, 1, and 2? How is "sequence" with any of those as the index outside of the possible index range?
def remove_duplicates(sequence):
new_list = sequence
for n in sequence:
for k in range(len(sequence)):
if n/(sequence[k]) == 1:
new_list.remove(sequence[k])
print new_list
remove_duplicates([1,2,3])
I strongly suggest Akavall's answer:
list(set(your_list))
As to why you get out of range errors: Python passes by reference, that is sequence and new_list still point at the same memory location. Changing new_list also changes sequence.
And finally, you are comparing items with themselves, and then remove them. So basically even if you used a copy of sequence, like:
new_list = list(sequence)
or
new_list = sequence[:]
It would return an empty list.
Your error is concurrent modification of the list:
for k in range(len(sequence)):
if n/(sequence[k]) == 1:
new_list.remove(sequence[k])
It may seem removing from new_list shouldn't effect sequence, but you did new_list = sequence at the beginning of the function. This means new_list actually literally is sequence, perhaps what you meant is new_list=list(sequence), to copy the list?
If you accept that they are the same list, the error is obvious. When you remove items, the length, and the indexes change.
P.S. As mentioned in a comment by #Akavall, all you need is:
sequence=list(set(sequence))
To make sequence contain no dupes. Another option, if you need to preserve ordering, is:
from collections import OrderedDict
sequence=list(OrderedDict.fromkeys(sequence))
If you don't like list(set(your_list)) because it's not guaranteed to preserved order, you could grab the OrderedSet recipe and then do:
from ordered_set import OrderedSet
foo = list("face a dead cabbage")
print foo
print list(set(foo)) # Order might change
print list(OrderedSet(foo)) # Order preserved
# like #Akavall suggested
def remove_duplicates(sequence):
# returns unsorted unique list
return list(set(sequence))
# create a list, if ele from input not in that list, append.
def remove_duplicates(sequence):
lst = []
for i in sequence:
if i not in lst:
lst.append(i)
# returns unsorted unique list
return lst