Exhaustion of iterator by zip in Python [duplicate] - python

This question already has answers here:
Zipped Python generators with 2nd one being shorter: how to retrieve element that is silently consumed
(8 answers)
Closed 1 year ago.
just out of curiosity I wanted to ask, why is the following wanted behavior in Python?
Suppose we have:
a = [1,2,3]
b = [1,2,3]
c = [1,2,3,4]
ai = iter(a)
bi = iter(b)
ci = iter(c)
Now, I expected the following example to print [4], however, it prints [].
for _ in zip(ci, zip(ai, bi)):
pass
print(list(ci))
Console:
>>> print(list(ci))
[]
But when I change arguments of the outter zip, it prints what I expect ([4]).
for _ in zip(zip(ai, bi), ci):
pass
print(list(ci))
Console:
>>> print(list(ci))
[4]
Shouldn't both example print the same result? Thanks.

next() of a zip iterator will try to read the next element of each of its argument iterators in order. If any of them reports that it's exhausted, the zip iterator will stop and report that it's exhausted.
This means that it will perform an extra iteration on all the initial arguments that are longer than the shortest one. This means that it reads an extra element of c.
You can see this ordering and extra iteration in the equivalent code in the documentation.
Change c to [1, 2, 3, 4, 5] and you'll get [5] at the end.

Related

Why can't a list be constructed and modified in the same line?

For example, why is a not equal to b?
a = [1]
a.append(2)
print(a) # [1, 2]
b = [1].append(2)
print(b) # None
The syntax for b doesn't look wrong to me, but it is. I want to write one-liners to define a list (e.g. using a generator expression) and then append elements, but all I get is None.
It's because:
append, extend, sort and more list function are all "in-place".
What does "in-place" mean? it means it modifies the original variable directly, some things you would need:
l = sorted(l)
To modify the list, but append already does that, so:
l.append(3)
Will modify l already, don't need:
l = l.append(3)
If you do:
l = [1].append(2)
Yes it will modify the list of [1], but it would be lost in memory somewhere inaccessible, whereas l will become None as we discovered above.
To make it not "in-place", without using append either do:
l = l + [2]
Or:
l = [*l, 2]
The one-liner for b does these steps:
Defines a list [1]
Appends 2 to the list in-place
Append has no return, so b = None
The same is true for all list methods that alter the list in-place without a return. These are all None:
c = [1].extend([2])
d = [2, 1].sort()
e = [1].insert(1, 2)
...
If you wanted a one-liner that is similar to your define and extend, you could do
c2 = [1, *[2]]
which you could use to combine two generator expressions.
All built-in methods under class 'List' in Python are just modifying the list 'in situ'. They only change the original list and return nothing.
The advantage is, you don't need to pass the object to the original variable every time you modify it. Meanwhile, you can't accumulatively call its methods in one line of code such as what is used in Javascript. Because Javascript always turns its objects into DOM, but Python not.

How to rotate a list to given 'd positions in python3? [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 3 years ago.
I tried solving this problem on hackerrank where you are given a list a and an integer d', you should rotate the list a to left d times and return the rotated list.
But, when I used this python code for a =[1,2,3,4,5] and d = 4 I got the output as [1,1,1,1,1] instead of [5,1,2,3,4].
temp = a
for j in range(len(a)):
a[j-d] = temp[j]
return a
But when I explicitly copied each element of list 'a' into the list 'temp' it worked fine and I passed all the test cases.
temp = []
for i in range(len(a)):
temp.append(a[i])
for j in range(len(a)):
a[j-d]=temp[j]
return a
Can somebody explain what was wrong with the earlier code?? Thank you!
temp = a
This is a reference assignment. You merely created another reference pointing to the same underlying list object.
temp = a[:]
This will create a new object and assign temp to the new object. (So does your loop of explicitly copying)
This is because list is a mutable type in python - so new objects are not created upon assignment.
You set temp = a which indicate that they are referring to the same pointer
a simple check you could do is to check their memory address
id(temp)
id(a)
You will notice both temp and a referring to the same address therefore changes done on a will also affect temp and vice versa.
In your second method, you created a new list instead of assigning it using an existing list, therefore the address are not similar and they are not referencing one another.
itertools.cycle is your friend for this:
import itertools
def rotate(l, n):
it = itertools.cycle(l)
for _ in range(n):
next(it)
return [next(it) for _ in range(len(l))]
print(rotate([1,2,3,4,5], 4))
result:
[5, 1, 2, 3, 4]
Here you have the live example
a =[1,2,3,4,5]
d = 4
for i in range(0,4):
# repeat the below steps for d times
temp=a[0] # store the a[0] in temp
for j in range(0,len(a)-1):
a[j]=a[j+1] # move all elements located in 1 to len(a)-1 to its previous location
a[len(a)-1]=temp # store the temp in a[len(a)-1]
print(a)
output:
[5, 1, 2, 3, 4]

Python: list(filter object) empties the object [duplicate]

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 5 years ago.
guys!
I'm using Python 3.6.1 and got into an interesting issue:
I'm using a simple itertools.filter() to get a sub-list from an items list, and then I just print it twice.
items = [1,2,3,4,5]
operateVersions = filter(lambda t: t, items)
print ("1: %s" % list(operateVersions))
print ("2: %s" % list(operateVersions))
The result is weird:
1: [1, 2, 3, 4, 5]
2: []
so, when i run list(operateVersions) it somehow rewrites operateVersions filter object instead of just returning the list interpretation
Is it an OK behavior? It doesn't look for me it is
A filter is a special iterable object, and like a generator, you can only iterate over it once. So essentially it returns an empty list when you run it a second time.

list.append() in python returning null [duplicate]

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.
What is the actual difference between list1.append() and list1+list2 in python??
Along with this, why the following statement return NULL?
print(list1.append(list2))
{where list1 and list2 are 2 simple list}
list.append() modifies the object and returns None.
[] + [] creates and "returns" new list.
https://docs.python.org/2.7/tutorial/datastructures.html#more-on-lists
Recommended reading: http://docs.python-guide.org/en/latest/writing/gotchas/
Returning None is a way to communicate that an operation is side-effecting -- that is, that it's changing one of its operands, as opposed to leaving them unchanged and returning a new value.
list1.append(list2)
...changes list1, making it a member of this category.
Compare the following two chunks of code:
# in this case, it's obvious that list1 was changed
list1.append(list2)
print list1
...and:
# in this case, you as a reader don't know if list1 was changed,
# unless you already know the semantics of list.append.
print list1.append(list2)
Forbidding the latter (by making it useless) thus enhances the readability of the language.
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> a.append(b) # append just appends the variable to the next index and returns None
>>> print a
[1,2,3,[4,5,6]]
>>> a.extend(b) # Extend takes a list as input and extends the main list
[1,2,3,4,5,6]
>>> a+b # + is exactly same as extend
[1,2,3,4,5,6]
When you print a function, you print what it returns and the append method does not return anything. However your list now has a new element. You can print the list to see the changes made.
list1 + list2 means that you combine 2 lists into one big list.
list1.append(element) adds one element to the end of the list.
Here's an example of append vs +
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> a + b
[1, 2, 3, 4, 5, 6]
>>>
>>> a.append(b)
>>> a
[1, 2, 3, [4, 5, 6]]

Python List concepts [duplicate]

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 7 years ago.
I am new to python programming
why this assignment value to k is giving 'None' value
> >>> l=[2,3,4]
> >>> k=l.append(14)
> >>> print k
None
> >>> print l
[2, 3, 4, 14]
in above example List,I append the 14 value to list and then assigned to k but k is printing None please tell me the reason why its printing None instead of appended list?
Thanks
mukthyar
append changes the current list and doesn't return anything. Use:
k = l + [14]
or
k = l[:] # Copy list
k.append(14)
Most methods in Python which mutate their instance (.append(), .sort(), et al.) do not return a copy of the object. Thus l.append(X) does actually return "None" just as l.sort() would.
You'd probably want to use something more like:
l.append(14)
k = l[-1]
In python default return type is None so if your function is not return any value then you will get the None from that function. There are different functions for the object. Some functions are perform on same object and others are return the modified copy. For example list.sort will change the original list while sorted will return the new sorted list without changing the original one. So append is working on object so it will change the object value instead of returning new modified copy.
Hope this will make your view clear about append method.
What you are seeing is expected - the list.append method does not return the modified list. If you take a look at the relevant section of the Python tutorial, you'll notice that methods which return useful values are documented as such.
Working in the interactive interpreter, you can tell that the expression yields None by the lack of output:
>>> l = [1, 2, 3]
>>> l.append(14)
>>>
If (theoretically) list.append returned the list, you would see the following instead:
>>> l = [1, 2, 3]
>>> l.append(14)
[1, 2, 3, 14]
>>>
Using the interactive interpreter this way can save you from printing every value.
from python document
list.append(x)
Add an item to the end of the list; equivalent to a[len(a):] = [x].
in simple word append function returns nothing but None
suggested reading

Categories