Python rule of for statement - python

I just began learning Python. So I am a beginner. I have a question about "for statement." I think I still don't know the rule of it.
Please see below.
example:
list1 = []
list2 = []
def forStatement():
for i in range(3):
for j in range(5, 7):
list2.append(j)
list1.append(list2)
return list1
The result I am looking for is;
[[5, 6], [5, 6], [5, 6]]
But when I run that code, it turns out like this.
[[5, 6, 5, 6, 5, 6], [5, 6, 5, 6, 5, 6], [5, 6, 5, 6, 5, 6]]
Can anyone help me? How can I get that result?
Thank you so much.

You are almost correct, the only problem with your code is that you keep adding elements to list2. Instead, you should create a new list every time:
list1 = []
for i in range(3):
list2 = []
for j in range(5, 7):
list2.append(j)
list1.append(list2)

You are appending in the loop, where you want to reset list2 each iteration of i
list1 = []
for i in range(3):
list2 = []
for j in range(5, 7):
list2.append(j)
list1.append(list2)
>>> print list1
[[5, 6], [5, 6], [5, 6]]

For your code, list1 is a container object which takes references to an object to which list2 is bound. (Usually, such a object is mentioned as list2 for brevity.) After the execution of the code, list1 finally contains three elements (i.e. references to list2) and list2 obviously contains triple (outer loop executed 3 times) consecutive 5, 6 (every execution of inner loop append 5 and 6 to list2).
The following code should be what you expect:
list1 = []
list2 = None
for i in range(3):
list2 = [] # To create a new empty list object and let it bound to the variable list2 every outer loop.
for j in range(5, 7):
list2.append(j)
list1.append(list2)
In this code, after the execution, list1 contains three elements that are distinct objects. But they were all bound to the variable list2 in the past.

Related

create sub-list of order integers present in a list and store them in another nested list in python

I have an array list like this:
list = [1,2,3,4,9,1,12,9,8,7,8,9,10,12,16,1,2,3,4,5,6,7,8,9,10]
I want to create a sub-list from a list of ordered numbers (which are already in sequence in arr_list for e.g. 1,2,3,4 are already in order, similarly 7,8,9,10 and last 10 numbers)
Final output will look like this:
[[1,2,3,4],[7,8,9,10],[1,2,3,4,5,6,7,8,9,10]]
Tried comparing if the i'th element of first for loop is less than the j'th element of second for loop.
This is what i've tried:
sub_list=[]
for i in range(0,length_of_list):
for j in range(i+1,length_of_list):
if (arr_list[i] < arr_list[j]):
sub_list.append(arr_list[i])
else:
pass
New to python, any leads are much appreciated.
Try this...
res, temp = [], []
lst = [1,2,3,4,9,1,12,9,8,7,8,9,10,12,16,1,2,3,4,5,6,7,8,9,10]
for i in lst:
if (not temp) or (temp[-1] == i-1):
temp.append(i)
else:
res.append(temp)
temp = [i]
res.append(temp)
print([i for i in res if len(i)>1])
Outputs:
[[1, 2, 3, 4], [7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
tell me if its okay for you...

Python - reordering items in list by moving some items to the front while keeping the rest in the same order

I am trying to reorder items in a list in a way illustrated by the following example:
Suppose the list before reordering is:
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
I want to implement a method called reorder_list(list, custom_order) such that:
list1 = reorder_list(list1, [3, 6, 12, 9])
print(list1)
Out: [3, 6, 9, 1, 2, 4, 5, 7, 8, 10]
Explanation: [3, 6, 12, 9] is a custom order I am specifying. 12 is not in list1 so it will be ignored. 3,6,9 are in list1, so they get moved to the front of the list and their order is the same as in [3, 6, 12, 9]. The remaining items in list1 are after 3,6,9 and in the original order.
Is there is an easier way (and a Pythonic way) than implementing the C-like loop code. For my purpose I care more about code simplicity than performance.
def reorder_list(items, early):
moved = [item for item in early if item in items]
remain = [item for item in items if item not in moved]
return moved + remain
This is really the same algorithm as Gireesh and Stephen Rauch wrote. Gireesh's version is written as it would be before list comprehensions, while Stephen's uses sets for faster lookups (but converts both input lists to sets; one should suffice) and extends with a generator expression instead of allocating a second list.
One thing of note is that we've assumed items are unique within the lists. Both in and set expect this.
00sdf0's answer uses a very different algorithm that might make sense in Haskell, with its lazy evaluation and tail call optimization, but in this case seems neither easily understood nor performant. It can be more clearly rewritten using slices:
def reorder_list(items, early):
result = list(items)
for move in reversed(early):
try:
place = result.index(move)
result = [result[place]] + result[:place] + result[place+1:]
except ValueError:
pass # this item wasn't in the list
This does allocate more lists, effectively shallow copying the list twice per moved item. Using islice instead of slice produced lazy evaluation that avoided one of those copies.
def reorder_list(list_main, custom_order):
# initializing empty list
list1 = list()
# to add values of custom list to list1 which are present in main list
for value in custom_order:
# add only the values which are present in main list
if value in list_main:
list1.append(value)
# to add remaining element of main list to list1 which are not present in list1
for value in list_main:
if value not in list1:
list1.append(value)
return list1
list1 = [1,2,3,4,5,6,7,8,9,10]
list1 = reorder_list(list1, [3,6,12,9])
print(list1)
A couple of list comprehensions should be reasonably performant for this:
Code:
def reorder_list(list_to_reorder, custom_order):
new_list = [x for x in custom_order if x in set(list_to_reorder)]
new_list.extend(x for x in list_to_reorder if x not in set(custom_order))
return new_list
Test Code:
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(reorder_list(list1, [9, 6, 3, 12]))
Results:
[9, 6, 3, 1, 2, 4, 5, 7, 8, 10]
The problem may be solved in the following way using itertools.chain and itertools.islice.
from itertools import chain, islice
lst = [1,2,3,4,5,6,7,8,9,10]
items_to_move = [9,6,3,12]
# move index i to front of list
def front(seq, i):
item = islice(seq, i, i+1)
start = islice(seq, 0, i, None)
end = islice(seq, i+1, None)
return list(chain(item,start,end))
for item in reversed(items_to_move):
if item in lst:
lst = front(lst, lst.index(item))
Output:
[9, 6, 3, 1, 2, 4, 5, 7, 8, 10]

mapping the append function to a list

I want to do the following elegantly. I have a list:
list1 = [[1,2],[3,1,4,7],[5],[7,8]]
I'd like to append the number 1 to each element of the list, so that I have
list1 = [[1,2,1],[3,1,4,7,1],[5,1],[7,8,1]]
I'm trying to map this via
map(list.append([1]), vectors)
but this returns the error append() takes exactly one argument (0 given) and if I just try append([1]) (without list.), I get NameError: global name 'append' is not defined. I guess I could do it with a loop, but this seems more elegant, is there a way to map this correctly?
Here is a several ways to implement what you want:
More readable and classic way
for el in list1:
el.append(1)
List comprehension
list1 = [el + [1] for el in list1]
Generators:
list1 = (el + [1] for el in list1)
Map
list1 = map(lambda el: el + [1], list1)
What to use?
It depends on you own situation and may depends on execution speed optimizations, code readability, place of usage.
Map is a worst choice in case of readability and execution speed
For is a fastest and more plain way to do this
Generators allows you to generate new list only when you really need this
List comprehension - one liner for classic for and it takes advantage when you need quickly filter the new list using if
i.e. if you need only add element to each item - for loop is a best choice to do this, but if you need add item only if item > 40, then you may consider to use List comprehension.
For example:
Classic For
x = 41
for el in list1:
if x > 40:
el.append(x)
List comprehension
x = 1
list1 = [el + [x] for el in list1 if x > 40]
as #jmd_dk mentioned, in this sample is one fundamental difference: with simple for you can just append to an existing object of the list which makes much less impact to execution time and memory usage. When you use List comprehension, you will get new list object and in this case new list object for each item.
Try a list comprehension, taking advantage of the fact the adding lists concats them together.
new_list = [l + [1] for l in list1]
You can simply do
list1 = [[1,2],[3,1,4,7],[5],[7,8]]
for el in list1:
el.append(1)
map(lambda x: x + [1], list1)
you mean this?
list.append() have NO return (mean always return None)
With list comprehension and append, you can do:
list1 = [[1, 2], [3, 1, 4, 7], [5], [7, 8]]
[item.append(1) for item in list1]
print(list1) # Output: [[1, 2, 1], [3, 1, 4, 7, 1], [5, 1], [7, 8, 1]]
Output:
>>> list1 = [[1, 2], [3, 1, 4, 7], [5], [7, 8]]
>>> [item.append(1) for item in list1]
[None, None, None, None]
>>> list1
[[1, 2, 1], [3, 1, 4, 7, 1], [5, 1], [7, 8, 1]]
You may also use extend like this:
[item.extend([1]) for item in list1]
print(list1) # Output: [[1, 2, 1], [3, 1, 4, 7, 1], [5, 1], [7, 8, 1]]

split list into sublists [duplicate]

This question already has answers here:
Loop "Forgets" to Remove Some Items [duplicate]
(10 answers)
Closed 8 years ago.
Define a function split_list that takes in a list of numbers and a number a and splits it into two sublists: list1 that contains numbers smaller than or equal to a, and another list, list2 containing numbers greater than a. list1 and list2 must be returned as elements of a tuple.
My code:
def split_list(lst, a):
list1 = []
list2 = []
for i in lst:
if i <= a:
list1.append(i)
lst.remove(i)
elif i > a:
list2.append(i)
lst.remove(i)
return (list1, list2)
Test code:
split_list([1, 10, 4, 9, 7, 2, 5, 8, 3, 4, 9, 6, 2], 5)
should give: ([1, 4, 2, 5, 3, 4, 2], [10, 9, 7, 8, 9, 6])
But I got ([1, 4, 5, 3, 2], [7, 9]) instead. Whats wrong with my code?
As commented by Martijn, you're breaking your list lst by trying to iterate through it and remove from it at the same time.
You don't need to remove from lst, so you can remove those lines.
Or, you could iterate over a copy of lst, whilst removing from the original lst.
To do this, simply change your for loop to be:
for i in lst[:]
This will copy a slice corresponding to the whole of lst for you to iterate over.
To avoid skipping elements you can alternatively loop through the list backwards deleting as you go. Here's an example using list indexes instead of the "for listitem in list" construct.
def split_list(lst, a):
list1 = []
list2 = []
for x in range(len(lst)-1,-1,-1):
if lst[x] <= a:
list1.append(lst[x])
del lst[x]
elif lst[x] > a:
list2.append(lst[x])
del lst[x]
return (list1, list2)
print split_list([1, 10, 4, 9, 7, 2, 5, 8, 3, 4, 9, 6, 2], 5)
# outputs ([2, 4, 3, 5, 2, 4, 1], [6, 9, 8, 7, 9, 10])
Modifying a list while iterating over it is always going to end badly. I would do instead:
for i in lst[:]: # Make a shallow copy.
#stuff
We are then iterating over that unmodified copy, so based on this we can edit the original safely.
Or just don't modify the list at all, meaning you can remove all uses of lst.remove(i) which should also fix the problem.
def split_list(lst, a):
list1 = []
list2 = []
for i in lst:
if i <= a:
list1.append(i)
elif i > a:
list2.append(i)
return (list1, list2)
There's no need to remove the items from the lst list as you iterate through it.

Modifying list contents in Python

I have a list like:
list = [[1,2,3],[4,5,6],[7,8,9]]
I want to append a number at the start of every value in the list programmatically, say the number is 9. I want the new list to be like:
list = [[9,1,2,3],[9,4,5,6],[9,7,8,9]]
How do I go about doing this in Python? I know it is a very trivial question but I couldn't find a way to get this done.
for sublist in thelist:
sublist.insert(0, 9)
don't use built-in names such as list for your own stuff, that's just a stupid accident in the making -- call YOUR stuff mylist or thelist or the like, not list.
Edit: as the OP aks how to insert > 1 item at the start of each sublist, let me point out that the most efficient way is by assignment of the multiple items to a slice of each sublist (most list mutators can be seen as readable alternatives to slice assignments;-), i.e.:
for sublist in thelist:
sublist[0:0] = 8, 9
sublist[0:0] is the empty slice at the start of sublist, and by assigning items to it you're inserting the items at that very spot.
>>> someList = [[1,2,3],[4,5,6],[7,8,9]]
>>> someList = [[9] + i for i in someList]
>>> someList
[[9, 1, 2, 3], [9, 4, 5, 6], [9, 7, 8, 9]]
(someList because list is already used by python)
Use the insert method, which modifies the list in place:
>>> numberlists = [[1,2,3],[4,5,6]]
>>> for numberlist in numberlists:
... numberlist.insert(0,9)
...
>>> numberlists
[[9, 1, 2, 3], [9, 4, 5, 6]]
or, more succintly
[numberlist.insert(0,9) for numberlist in numberlists]
or, differently, using list concatenation, which creates a new list
newnumberlists = [[9] + numberlist for numberlist in numberlists]
If you're going to be doing a lot of prepending,
perhaps consider using deques* instead of lists:
>>> mylist = [[1,2,3],[4,5,6],[7,8,9]]
>>> from collections import deque
>>> mydeque = deque()
>>> for li in mylist:
... mydeque.append(deque(li))
...
>>> mydeque
deque([deque([1, 2, 3]), deque([4, 5, 6]), deque([7, 8, 9])])
>>> for di in mydeque:
... di.appendleft(9)
...
>>> mydeque
deque([deque([9, 1, 2, 3]), deque([9, 4, 5, 6]), deque([9, 7, 8, 9])])
*Deques are a generalization of stacks and queues (the name is pronounced "deck" and is short for "double-ended queue"). Deques support thread-safe, memory-efficient appends and pops from either side of the deque with approximately the same O(1) performance in either direction.
And, as others have mercifully mentioned:
For the love of all things dull and ugly,
please do not name variables after your favorite data-structures.
#!/usr/bin/env python
def addNine(val):
val.insert(0,9)
return val
if __name__ == '__main__':
s = [[1,2,3],[4,5,6],[7,8,9]]
print map(addNine,s)
Output:
[[9, 1, 2, 3], [9, 4, 5, 6], [9, 7, 8, 9]]

Categories