Pythonic Referenced For Loop [duplicate] - python

This question already has answers here:
Python Referenced For Loop
(3 answers)
Closed 8 years ago.
I have a for loop as follows:
a=[1,2,3,4,5]
for i in a:
i=6
What I would like is for every element of a to become 6.
Now I know that this for loop won't do it, because I am merely changing the what i refers to.
I instead could write:
a=[1,2,3,4,5]
for i in len(range(a)):
a[i]=6
But that doesn't seem very Pythonic. What are good ways of doing this sort of thing? Obviously, setting everything to 6 is contrived example and, in reality, I would be doing more complicated (and wonderful) things. Therefore, answers should be generalised.

The for-variable is always a simple value, not a reference; there is no way to know that it came from a list and thus write back to the list on changing.
The len(a) approach is the usual idiom, although you need range (or xrange) too:
for i in range(len(a)):
or, just as commonly, use the enumerate function to get indexes as well as values:
for i, v in enumerate(a):
a[i]= v+1
a list comprehension might be a good alternative, eg:
a= [6 for v in a]

This would probably be a good use for map() depending on what you're doing in real life. For example:
a = map(lambda x: 6, a)

You could use:
>>> a = [1, 2, 3, 4, 5]
>>> a = [6] * len(a)
>>> a
[6, 6, 6, 6, 6]

Related

Pythonic way to move elements from one list to another? [duplicate]

This question already has answers here:
How can I partition (split up, divide) a list based on a condition?
(41 answers)
Closed 1 year ago.
I'm struggling to find a pythonic way to move things from one list to another.
Eg.
list_of_things = [1, 2, 3, 4]
is_odd = lambda x: x % 2 != 0
odd_list = some_pythonic_operation(list_of_things, is_odd)
assert list_of_things == [2, 4]
assert odd_list == [1, 3]
Note: Please do not hyperfocus on the even/odd example and give a solution that handles just that case well, I'm looking for a general solution to this problem.
Note: I care very much about the performance and making sure this can be done in one pass, ideally in a readable pythonic way.
Your best bet might be to enumerate over the original list, popping things off it as you go.
list_of_things = [1, 2, 3, 4]
odd_list = [list_of_things.pop(i) for i, num in enumerate(list_of_things) if num % 2]
assert list_of_things == [2, 4]
assert odd_list == [1, 3]
Be warned: you are asking about a "Pythonic" way to do this. The Pythonic way is to create one list from another without touching the first list. The reason is mutating a collection as you iterate over it has lots of pitfalls you have to be worried about.

Remove a specific item from a list by iterating [duplicate]

This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 5 years ago.
I want to remove specific items from python list by iterating and checking if it meet some requirements. At first, I just operate on a list of customized class objects, but it actually meet some errors, and I experiment on a python list of primitive type int, just to find strange result!
Here is some code excerpts:
>>> a=[1,2,3,4,5]
>>> for i in a:
... a.remove(i)
...
>>> a
[2, 4]
I expect the a should be [] after the loop, but it proves to be [2,4], I wonder why actually. I found a related question in Remove items from a list while iterating, but it only gives a solution on how to remove specific items, not concerning the mechanism actually. I really want to know the reason of this strange result.
lets try to print the values of i and a while iterating.
for i in a:
print i, a
a.remove(i)
the output will be:
1 [1, 2, 3, 4, 5]
3 [2, 3, 4, 5]
5 [2, 4, 5]
so when you remove an element, the indices will change, so while value at index 1 was 2 earlier, now it is 3. This will be the value of i.
So you've exposed a little of the python implementation. Basically, an array powers the python list, and it is simply incrementing the array index by 1. So it'll go to a[0], a[1], a[2]... and check before each iteration that it's not gonna run off the end of the array. As you remove the first item '1' from the list, '2' moves to a[0]. The array now looks like [2,3,4,5]. The iterator is now pointing to a[1], so now '3' gets removed. Finally, skipping over '4', '5' gets removed.
a = [1,2,3,4,5]
for i in a:
print("a:%s i=%s"%(a,i))
a.remove(i)
print("final a: %s"%a)
Gives the output
a:[1, 2, 3, 4, 5] i=1
a:[2, 3, 4, 5] i=3
a:[2, 4, 5] i=5
final a: [2, 4]
Here's the real nuts and bolts if you're interested.
https://github.com/python/cpython/blob/master/Objects/listobject.c#L2832
The reason your solution doesn't work as expected is because the iterator doesn't behave the way you'd expect if the list is modified. If you're example was rewritten this way, you'd get the result you expect.
>>> a=[1,2,3,4,5]
>>> b = a[:]
>>> for i in b:
... a.remove(i)
...
>>> a
[]
This is because 'b' is a copy of 'a', so be doesn't get modified when a does. This means the iterator doesn't have the data structure modified underneath it.
A more efficient solution is:
a = [1,2,3,4,5]
a = [i for i in a if not condition(i)]
This list comprehension copies as it goes through the source list, and only bothers to copy the elements that aren't being removed.

Going through a list [duplicate]

This question already has answers here:
Efficient way to rotate a list in python
(27 answers)
Closed 9 years ago.
Say you have a list [1,2,3,4]
And I want to get [2,3,4,1] or [3,4,1,2].
Basically I am using the list with a different starting point each time, but then continuing through the list. How would I create something to recognize that in python.
What i have now is list[n:] where n is the shifted value, say 2, making you start at three.
someList[n:] + someList[:n]
would solve your purpose if n <= len(someList)
Also, collections.deque is the efficient way.
I believe this is what you want
>>> def startAt(index, list):
... print list[index:] + list[:index]
...
>>> l = [0,1,2,3,4,5]
>>> startAt(3, l)
[3, 4, 5, 0, 1, 2]
>>>

proper use of list comprehensions - python

Normally, list comprehensions are used to derive a new list from an existing list. Eg:
>>> a = [1, 2, 3, 4, 5]
>>> [i for i in a if i > 2]
[3, 4, 5]
Should we use them to perform other procedures? Eg:
>>> a = [1, 2, 3, 4, 5]
>>> b = []
>>> [b.append(i) for i in a]
[None, None, None, None, None]
>>> print b
[1, 2, 3, 4, 5]
or should I avoid the above and use the following instead?:
for i in a:
b.append(i)
You should indeed avoid using list comprehensions (along with dictionary comprehensions, set comprehensions and generator expressions) for side effects. Apart from the fact that they'd accumulate a bogus list and thus waste memory, it's also confusing. I expect a list comprehension to generate a (meaningful) value, and many would agree. Loops, on the other hand, are clearly a sequence of statements. They are expected to kick off side effects and generate no result value - no surprise.
From python documentation:
List comprehensions provide a concise way to create lists. Common
applications are to make new lists
Perhaps you want to learn more about reduce(), filter() and map() functions.
In the example you give it would make the most sense to do:
b = [i for i in a]
if for some reason you wanted to create b. In general, there is some common sense that must be employed. If using a comprehension makes your code unreadable, don't use it. Otherwise go for it.
Only use list comprehensions if you plan to use the created list. Otherwise you create it just for the GC to throw it again without ever being used.
So instead of [b.append(i) for i in a] you should use a proper for loop:
for i in a:
b.append(i)
Another solution would be through a generator expression:
b += (i for i in a)
However, if you want to append the whole list, you can simply do
b += a
And if you just need to apply a function to the elements before adding them to the list, you can always use map:
b += map(somefunc, a)
b = []
a = [1, 2, 3, 4, 5]
b.extend (a)

Moving values but preserving order in a Python list [duplicate]

This question already has answers here:
Python list rotation [duplicate]
(4 answers)
Closed 7 years ago.
I have a list
a=[1,2,3,4,5]
and want to 'move' its values so it changes into
a=[2,3,4,5,1]
and the next step
a=[3,4,5,1,2]
Is there a built-in function in Python to do that?
Or is there a shorter or nicer way than
b=[a[-1]]; b.extend(a[:-1]); a=b
>>> a = [1,2,3,4,5]
>>> a.append(a.pop(0))
>>> a
[2, 3, 4, 5, 1]
This is expensive, though, as it has to shift the contents of the entire list, which is O(n). A better choice may be to use collections.deque if it is available in your version of Python, which allow objects to be inserted and removed from either end in approximately O(1) time:
>>> a = collections.deque([1,2,3,4,5])
>>> a
deque([1, 2, 3, 4, 5])
>>> a.rotate(-1)
>>> a
deque([2, 3, 4, 5, 1])
Note also that both these solutions involve changing the original sequence object, whereas yours creates a new list and assigns it to a. So if we did:
>>> c = a
>>> # rotate a
With your method, c would continue to refer to the original, unrotated list, and with my methods, it will refer to the updated, rotated list/deque.

Categories