Variables scope for nested python for-loop [duplicate] - python

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 6 years ago.
I have two nested for loops and two lists, I want one of tle list to re-initialize after one iteration of inner loop.
def test():
i = ['1','5','9','3','6','4']
for x in xrange(0,len(i)):
j = ['6', '7', '9', '3']
newi = i
for y in xrange(0,len(j)):
newi[x] = j[y]
print "i", i
print "end of one iteration on finner loop"
print "newi", newi
test()
Its a dummy code, I want a clean new instance of newi to be that of i after one iteration of inner loop, currently it preserver the value of inner loop
current output:
i ['6', '5', '9', '3', '6', '4']
i ['7', '5', '9', '3', '6', '4']
i ['9', '5', '9', '3', '6', '4']
i ['3', '5', '9', '3', '6', '4']
end of one iteration on inner loop
newi ['3', '5', '9', '3', '6', '4']
i ['3', '6', '9', '3', '6', '4']
i ['3', '7', '9', '3', '6', '4']
i ['3', '9', '9', '3', '6', '4']
i ['3', '3', '9', '3', '6', '4']
end of one iteration on inner loop
newi ['3', '3', '9', '3', '6', '4']
i ['3', '3', '6', '3', '6', '4']
i ['3', '3', '7', '3', '6', '4']
i ['3', '3', '9', '3', '6', '4']
i ['3', '3', '3', '3', '6', '4']
end of one iteration on inner loop
newi ['3', '3', '3', '3', '6', '4']
i ['3', '3', '3', '6', '6', '4']
i ['3', '3', '3', '7', '6', '4']
i ['3', '3', '3', '9', '6', '4']
i ['3', '3', '3', '3', '6', '4']
end of one iteration on inner loop
newi ['3', '3', '3', '3', '6', '4']
i ['3', '3', '3', '3', '6', '4']
i ['3', '3', '3', '3', '7', '4']
i ['3', '3', '3', '3', '9', '4']
i ['3', '3', '3', '3', '3', '4']
end of one iteration on inner loop
newi ['3', '3', '3', '3', '3', '4']
i ['3', '3', '3', '3', '3', '6']
i ['3', '3', '3', '3', '3', '7']
i ['3', '3', '3', '3', '3', '9']
i ['3', '3', '3', '3', '3', '3']
end of one iteration on inner loop
newi ['3', '3', '3', '3', '3', '3']

Instead of:
newi = i
replace with:
newi = list(i) # list(i) creates another copy i

Related

Insertion Sort not working for single digit entries if #entries> 9

I am trying to implement insertion sort using python. Below is my code:
import numpy as np
N=int(input())
A=input().split()
#A=[int(x) for x in input().split()]
B_sorted=A.copy()
C= A.copy()
def inssort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i-1
while (j >=0 and key < arr[j]):
arr[j+1] = arr[j]
j -= 1
arr[j+1] = key
inssort(B_sorted)
for i in range(0,len(A)):
for j in range(0,len(A)):
if A[i]==B_sorted[j]:
C[i]=j+1
break
j=j+1
i=i+1
for x in B_sorted:
print (x, "",end="")
My code works for the following set of entries:
[9,8,7,...,2,1]
[20,19,...,12,11]
[20,19,...,11,10]
but it doesn't work for following
[10,9,8,...,2,1]
I don't understand what exactly is the issue here.
I tried to go to the detail by printing the output at every loop:
10 9 8 7 6 5 4 3 2 1
['10', '9', '8', '7', '6', '5', '4', '3', '2', '1']
['10', '8', '9', '7', '6', '5', '4', '3', '2', '1']
['10', '7', '8', '9', '6', '5', '4', '3', '2', '1']
['10', '6', '7', '8', '9', '5', '4', '3', '2', '1']
['10', '5', '6', '7', '8', '9', '4', '3', '2', '1']
['10', '4', '5', '6', '7', '8', '9', '3', '2', '1']
['10', '3', '4', '5', '6', '7', '8', '9', '2', '1']
['10', '2', '3', '4', '5', '6', '7', '8', '9', '1']
['1', '10', '2', '3', '4', '5', '6', '7', '8', '9']
Looks like for some reason at the first iteration j is not taking the value 0 for this particular sequence. As I mentioned before, it works perfectly for a lot of other sequences.
Kindly help.

Trying to solve with python map function with lambda expression inside for loop

n=10
fun=list(map(lambda x:[j for j in range(x)],n))
print(fun)
expected output is:
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
# using map (map works on an iterable)
n=10
fun=lambda x: (range(x)) # remember this is a function (so call it)
fun=list(map(str, fun(n)))
print(fun)
# directly
n=10
fun=list(map(str, (range(n))))
print(fun)
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
Python docs for reference:
map(): https://docs.python.org/3/library/functions.html#map
range(): https://docs.python.org/3/library/functions.html#func-range
lambda(): https://docs.python.org/3/library/ast.html?highlight=lambda#ast.Lambda

how to sort python list in a way that if 1 should come before and 10 and 2 before 20

['2', '8', '2', '3', '6', '4', '1', '1', '10', '6', '3', '3', '6', '1', '3', '8', '4', '6', '1', '10', '8', '4', '10', '4', '1', '3', '2', '3', '2', '6', '1', '5', '2', '9', '8', '5', '10', '8', '7', '9', '6', '4', '2', '6', '3', '8', '8', '9', '8', '2', '9', '10', '3', '10', '7', '5', '7', '1', '7', '5', '1', '4', '7', '6', '1', '10', '5', '4', '8', '4', '2', '7', '8', '1', '1', '7', '4', '1', '1', '9', '8', '6', '5', '9', '9', '3', '7', '6', '3', '10', '8', '10', '7', '2', '5', '1', '1', '9', '9', '5']
after using lambda function inf following way:
a.sort(key=lambda a: int(a.split()[0]))
a = a[::-1]
I got
['10', '10', '10', '10', '10', '10', '10', '10', '10', '9', '9', '9', '9', '9', '9', '9', '9', '9', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '7', '7', '7', '7', '7', '7', '7', '7', '7', '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', '5', '5', '5', '5', '5', '5', '5', '5', '4', '4', '4', '4', '4', '4', '4', '4', '4', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '2', '2', '2', '2', '2', '2', '2', '2', '2', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1']
But i want
10 in end after 1 , likewise if put 20 and 2 in list than 2 should come before 20 and 20 before 10 etc
The operation:
a.sort()
with no other options sets a to:
['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '10', '10', '10', '10', '10', '10', '10', '10', '10', '2', '2', '2', '2', '2', '2', '2', '2', '2', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '4', '4', '4', '4', '4', '4', '4', '4', '4', '5', '5', '5', '5', '5', '5', '5', '5', '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', '7', '7', '7', '7', '7', '7', '7', '7', '7', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '9', '9', '9', '9', '9', '9', '9', '9', '9']
You want an ordered list of strings. Those strings are representations of numbers. Now you want a grouped sorting. First everything that starts with a '9', then '8' and down to '1'. In each of those groups the values should be sorted in numeric order.
An example list:
a = ['11', '105', '2', '8', '2', '3', '6', '4', '1', '1', '10', '81', '3', '3', '5', '10', '8', '7', '9', '6', '4', '2']
Now let's do a grouped sorting with a.sort(key=lambda v: v[0]):
['11', '105', '1', '1', '10', '10', '2', '2', '2', '3', '3', '3', '4', '4', '5', '6', '6', '7', '8', '81', '8', '9']
We see, that the values are grouped now, but we want the values starting with '9' first. We're going to fix this by reversing the result with a.sort(key=lambda v: v[0], reversed=True)
['9', '8', '81', '8', '7', '6', '6', '5', '4', '4', '3', '3', '3', '2', '2', '2', '11', '105', '1', '1', '10', '10']
The groups are correct, now we have to sort the values in the groups. So after the sorting according to the first character we have to sort the value by number. That's easy, we just have to create a tuple for the key: a.sort(key=lambda v: (v[0], int(v)), reverse=True)
['9', '81', '8', '8', '7', '6', '6', '5', '4', '4', '3', '3', '3', '2', '2', '2', '105', '11', '10', '10', '1', '1']
OK, the values are sorted now, but we have to reverse them in the groups. The easiest way to do that ist to take the negative number: a.sort(key=lambda v: (v[0], -int(v)), reverse=True).
['9', '8', '8', '81', '7', '6', '6', '5', '4', '4', '3', '3', '3', '2', '2', '2', '1', '1', '10', '10', '11', '105']
you can use the following sample using key=str
integers = ['2', '8', '2', '3', '6', '4', '1', '1', '10', '6', '3', '3', '6', '1', '3', '8', '4', '6', '1', '10', '8', '4', '10', '4', '1', '3', '2', '3', '2', '6', '1', '5', '2', '9', '8', '5', '10', '8', '7', '9', '6', '4', '2', '6', '3', '8', '8', '9', '8', '2', '9', '10', '3', '10', '7', '5', '7', '1', '7', '5', '1', '4', '7', '6', '1', '10', '5', '4', '8', '4', '2', '7', '8', '1', '1', '7', '4', '1', '1', '9', '8', '6', '5', '9', '9', '3', '7', '6', '3', '10', '8', '10', '7', '2', '5', '1', '1', '9', '9', '5']
print(sorted(integers, key=str))
you don't need to use lambda method here. Instead of using lambda you can use '.sort()' method to sort the items in the list. like this one:
li=['2', '8', '2', '3', '6', '4', '1', '1', '10', '6', '3', '3', '6', '1', '3', '8', '4', '6', '1', '10', '8', '4', '10', '4', '1', '3', '2', '3', '2', '6', '1', '5', '2', '9', '8', '5', '10', '8', '7', '9', '6', '4', '2', '6', '3', '8', '8', '9', '8', '2', '9', '10', '3', '10', '7', '5', '7', '1', '7', '5', '1', '4', '7', '6', '1', '10', '5', '4', '8', '4', '2', '7', '8', '1', '1', '7', '4', '1', '1', '9', '8', '6', '5', '9', '9', '3', '7', '6', '3', '10', '8', '10', '7', '2', '5', '1', '1', '9', '9', '5','20']
li.sort()
print(li)
output:
['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '10', '10', '10', '10', '10', '10', '10', '10', '10', '2', '2', '2', '2', '2', '2', '2', '2', '2', '20', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '4', '4', '4', '4', '4', '4', '4', '4', '4', '5', '5', '5', '5', '5', '5', '5', '5', '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', '7', '7', '7', '7', '7', '7', '7', '7', '7', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', '9', '9', '9', '9', '9', '9', '9', '9', '9']
I hope you get your answere.
This might helps you:
a.sort(key=str)
or
new list = sorted(a, key=str) # if you dont want to change a
this will sort the list as you want even if the items are integer

Adding counter/index to a list of lists in Python

I have a list of lists of strings:
listBefore = [['4', '5', '1', '1'],
['4', '6', '1', '1'],
['4', '7', '8', '1'],
['1', '2', '1', '1'],
['2', '3', '1', '1'],
['7', '8', '1', '1'],
['7', '9', '1', '1'],
['2', '4', '3', '1']]
and I would like to add a counter/index in the middle of each list so that the list looks like:
listAfter = [['4', '5', '1', '1', '1'],
['4', '6', '2', '1', '1'],
['4', '7', '3', '8', '1'],
['1', '2', '4', '1', '1'],
['2', '3', '5', '1', '1'],
['7', '8', '6', '1', '1'],
['7', '9', '7', '1', '1'],
['2', '4', '8', '3', '1']]
What would be the easiest way to do so? I could probably loop over the lists and add the index, but is there a cleaner way to do so?
Cheers,
Kate
Edit:
The code I wrote works for me:
item = 1
for list in listBefore:
list.insert(2,str(item))
item = item + 1
print listBefore
I was wondering if there is another way to do so more efficiently or in one step.
Iterate over the parent list with enumerate() to get counter (used as i in the below example) along with list element. In the sublist, insert the i at the middle of sublist using list.insert(index, value) method.
Note: The value of counter i.e. i will be of int type, so you have to explicitly type cast it to str as str(i)before inserting. Below is the sample code:
for i, sub_list in enumerate(my_list, 1): # Here my_list is the list mentioned in question as 'listBefore'
sub_list.insert(len(sub_list)/2, str(i))
# Value of 'my_list'
# [['4', '5', '1', '1', '1'],
# ['4', '6', '2', '1', '1'],
# ['4', '7', '3', '8', '1'],
# ['1', '2', '4', '1', '1'],
# ['2', '3', '5', '1', '1'],
# ['7', '8', '6', '1', '1'],
# ['7', '9', '7', '1', '1'],
# ['2', '4', '8', '3', '1']]
You can perform this with a list comprehension
listAfter = [listBefore[i][:len(listBefore[i])/2] + [str(i+1)] + listBefore[i][len(listBefore[i])/2:] for i in range(len(listBefore))]
You should learn about enumerate, it lets you iterate over the list with two iterators - one (str_list in this case) holds the current item in the list, and the other (i`) holds it's index in the list.
for i,str_list in enumerate(listBefore):
listBefore[i] = str_list[:len(str_list)//2] + [str(i+1)] + str_list[len(str_list)//2:]
>>> data = [['4', '5', '1', '1'],
['4', '6', '1', '1'],
['4', '7', '8', '1'],
['1', '2', '1', '1'],
['2', '3', '1', '1'],
['7', '8', '1', '1'],
['7', '9', '1', '1'],
['2', '4', '3', '1']]
>>> print [row[:len(row)//2] + [str(i)] + row[len(row)//2:]
for i, row in enumerate(data, start=1)]
[['4', '5', '1', '1', '1'],
['4', '6', '2', '1', '1'],
['4', '7', '3', '8', '1'],
['1', '2', '4', '1', '1'],
['2', '3', '5', '1', '1'],
['7', '8', '6', '1', '1'],
['7', '9', '7', '1', '1'],
['2', '4', '8', '3', '1']]

Swap indexes using slices?

I know that you can swap 2 single indexes in Python
r = ['1', '2', '3', '4', '5', '6', '7', '8']
r[2], r[4] = r[4], r[2]
output:
['1', '2', '5', '4', '3', '6', '7', '8']
But why can't you swap 2 slices of indexes in python?
r = ['1', '2', '3', '4', '5', '6', '7', '8']
I want to swap the numbers 3 + 4 with 5 + 6 + 7 in r:
r[2:4], r[4:7] = r[4:7], r[2:4]
output:
['1', '2', '5', '6', '3', '4', '7', '8']
expected output:
['1', '2', '5', '6', '7', '3', '4', '8']
What did I wrong?
output:
The slicing is working as it should. You are replacing slices of different lengths. r[2:4] is two items, and r[4:7] is three items.
>>> r = ['1', '2', '3', '4', '5', '6', '7', '8']
>>> r[2:4]
['3', '4']
>>> r[4:7]
['5', '6', '7']
So when ['3', '4'] is replaced, it can only fit ['5', '6'], and when ['5', '6', '7'] is replaced, it only gets ['3', '4']. So you have ['1', '2',, then the next two elements are the first two elements from ['5', '6', '7'] which is just ['5', '6', then the two elements from ['3', '4' go next, then the remaining '7', '8'].
If you want to replace the slices, you have to start slices at the right places and allocate an appropriate size in the array for each slice:
>>> r = ['1', '2', '3', '4', '5', '6', '7', '8']
>>> r[2:5], r[5:7] = r[4:7], r[2:4]
>>> r
['1', '2', '5', '6', '7', '3', '4', '8']
old index: 4 5 6 2 3
new index: 2 3 4 5 6
Think of this:
r[2:4], r[4:7] = r[4:7], r[2:4]
as similar to this:
original_r = list(r)
r[2:4] = original_r[4:7]
r[4:7] = original_r[2:4]
So, by the time it gets to the third line of that, the 4th element isn't what you think it is anymore... You replaced '3', '4' with '5', '6', '7', and now the [4:7] slice starts with that '7'.
>>> r = ['1', '2', '3', '4', '5', '6', '7', '8']
>>> r[2:5], r[5:7] = r[4:7], r[2:4]
>>> r
['1', '2', '5', '6', '7', '3', '4', '8']
In your code:
>>> r[2:4], r[4:7] = r[4:7], r[2:4]
You are assigning r[4:7] which have 3 elements to r[2:4] which have only 2.
In the code I posted:
>>> >>> r[2:5], r[5:7] = r[4:7], r[2:4]
r[4:7] which is ['5', '6', '7'], replaces
r[2:5] which is ['3', '4', '5']
r resulting in ['1', '2', '5', '6', '7', '6', '7', '8']
and then:
r[2:4] which was ['3', '4'], replaces
r[5:7] which is ['6', '7']
So final result being:
['1', '2', '5', '6', '7', '3', '4', '8']

Categories

Resources