List of lists weird python issue [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 5 years ago.
list= []
x = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
for i in range(2):
list.append(x)
list[0][0]="x"
print list
And after printing I get this:
[['x', 'B', 'C', 'D', 'E', 'F', 'G'], ['x', 'B', 'C', 'D', 'E', 'F', 'G']]
The first item in every list was replaced by 'x' whereas I only wanted the first item in the first list to be replaced by 'x'(hence the line list[0][0]="x")

The line list.append(x) adds a reference to x into list. Both sublists end up pointing to the same object (as does x). In fact, doing x[0] = 'x' would have the exact same effect as list[0][0] = 'x'. To make the sub-lists independent, make a copy by doing list.append(x.copy()) or list.append(x[:])

Related

Listing in python [duplicate]

This question already has answers here:
How do I iterate through two lists in parallel?
(8 answers)
Closed 1 year ago.
I want to check if the index of list in my list is in same position, then after make the position same I want to print it
news_a = ['A', 'B', 'C', 'D']
news_b = ['E', 'F', 'G', 'H']
for i in news_a:
for j in news_b:
if i == j:
print(f"{i}\n{j}")
If I'm understanding your question correctly, all you have to change is that you need to reference the index of each element in your for-loop iterations, and the elements themselves when printing them.
news_a = ['A', 'B', 'C', 'D']
news_b = ['E', 'F', 'G', 'H']
for i in range(len(news_a)):
for j in range(len(news_b)):
if i == j:
print(f"{news_a[i]}\n{news_b[j]}")

How to create a new sublist from a list whose length depends on another list [duplicate]

This question already has answers here:
Splitting a string by list of indices
(4 answers)
Closed 4 years ago.
I would like to create a new list with sub-lists inside whose length depends on another list, for example I have:
a = [1,3,2,5,4]
b = ['a','b','c','d','e','f','g','h','i','l','m','n','o','p','q']
and I would like to have a nested list of the form:
[['a'],
['b', 'c', 'd'],
['e', 'f'],
['g', 'h', 'i', 'l', 'm'],
['n', 'o', 'p', 'q']]
Steps to solve this:
create an empty list
create a int done=0 that tells you how many things you already sliced from your data
loop over all elements of your "how to cut the other list in parts"-list
slice from done to done + whatever the current element of your "how to cut the other list in parts" is and append it to the empty list
increment done by whatever you just sliced
add the (if needed) remainder of your data
print it.
Doku:
Understanding Python's slice notation
How to "properly" print a list?
and infos about looping here: looping techniques PyTut
You can read about why we do not solve your homework for you here: open letter to students with homework problems
a = [1,3,2,5,4]
b = ['a','b','c','d','e','f','g','h','i','l','m','n','o','p','q']
out=[]
for number in a:
out.append(b[:number])
b=b[number:]
print(out)
#[['a'], ['b', 'c', 'd'], ['e', 'f'], ['g', 'h', 'i', 'l', 'm'], ['n', 'o', 'p', 'q']]
Description
The out is the final output list. The loop iterates through each element in list a (say 'number') and appends a list of that many elements from the start of list b to our output list. Then it proceeds to update list b so that those elements are removed.

Python array value unexpectedly changes after function call

I have a small function which uses one list to populate another. For some reason, the source list gets modified. I don't have a single line that manipulates the source list arr. I am probably missing the way Python deals with scope of variables, lists. My expected output is for the list arr to remain the same after the function call.
numTestRows = 5
m = 2
def getTestData():
data['test'] = []
size_c = len(arr)
for i in range(numTestRows):
data['test'].append(arr[i%size_c])
for j in range(m):
data['test'][i].append('xyz')
#just a 2x5 str matrix
arr = [['a', 'b', 'c', 'd', 'e'], ['f', 'g', 'h', 'i', 'j']]
print('Array before: ')
print( arr)
data = {}
getTestData()
print('Array after: ')
print( arr)
Output
Array before:
[['a', 'b', 'c', 'd', 'e'], ['f', 'g', 'h', 'i', 'j']]
Array after:
[['a', 'b', 'c', 'd', 'e', 'xyz', 'xyz', 'xyz', 'xyz', 'xyz', 'xyz'], ['f', 'g', 'h', 'i', 'j', 'xyz', 'xyz', 'xyz', 'xyz']]
You've mis-handled the references in your list of lists (not a matrix). Perhaps if we break this down a little more, you can see what's happening. Start your main program with the two char lists as separate variables:
left = ['a', 'b', 'c', 'd', 'e']
right = ['f', 'g', 'h', 'i', 'j']
arr = [left, right]
Now, look at what happens within your function at the critical lines. On this first iteration, size_c is 2, i is 0 ...
data['test'].append(arr[i%size_c])
This will append arr[0] to data[test], which started as an empty list. Now for the critical part: arr[0] is not a new list; rather, it's a reference to the list we now know as left in the main program. There is only one copy of this list.
Now, when we get into the next loop, we hit the statement:
data['test'][i].append('xyz')
data['test'][i] is a reference to the same list as left ... and this explains the appending to the original list.
You can easily copy a list with the suffix [:], making a new slice of the entire list. For instance:
data['test'].append(arr[i%size_c][:])
... and this should solve your reference problem.

Check list item against multiple lists and remove if present in any of them. Python [duplicate]

This question already has answers here:
remove elements in one list present in another list [duplicate]
(2 answers)
Closed 8 years ago.
I have a main list such as:
mainlst = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
and I want to search each item in this mainlst against multiple other search lists and if it's present in any of them to remove it from the main list, so for example:
searchlst1 = ['a', 'b', 'c']
searchlst2 = ['a', 'd', 'f']
searchlst3 = ['e', 'f', 'g']
The issue Im having is I cant work out how to make the loop go through each statement, so if I use and if elif statement it exits the loop as soon as it has found a match
for item in mainlst:
if item in searchlst1:
mainlst.remove(item)
elif item in searchlst2:
mainlst.remove(item)
elif item in searchlst3
mainlst.remove(item)
but obviously this exits the loop as soon as one condition is true, how do I make the loop go through all the conditions?
set objects are great for stuff like this -- the in operator takes O(1) time compared to O(N) time for a list -- And it's easy to create a set from a bunch of existing lists using set.union:
search_set = set().union(searchlst1, searchlst2, searchlst3)
mainlst = [x for x in mainlst if x not in search_set]
Example:
>>> search_set = set().union(searchlst1, searchlst2, searchlst3)
>>> search_set
set(['a', 'c', 'b', 'e', 'd', 'g', 'f'])
>>> mainlst = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
>>> mainlst = [x for x in mainlst if x not in search_set]
>>> mainlst
['h']
How about using a list comprehension and a set:
[i for i in mainlst if i not in set(searchlst1 + searchlst2 + searchlst3)]
returns ['h']
set() takes an iterable (in this case a group of lists) and returns a set containing the unique values. Tests for membership in a set always take the same amount of time, whereas testing for membership in a list scales linearly with the length of the list.
The list comprehension goes through each element of mainlst and constructs a new list whose members are not in the set:
>>> mainlst = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
>>> search = set(searchlst1 + searchlst2 + searchlst3)
>>> search
set(['a', 'c', 'b', 'e', 'd', 'g', 'f'])
>>> [i for i in mainlst if i not in search]
['h']
Replacing the elif statements with if statements will fix your problem.
for item in mainlst:
if item in searchlst1:
mainlst.remove(item)
if item in searchlst2:
mainlst.remove(item)
if item in searchlst3:
mainlst.remove(item)
The problem now is that your doing three searches through the list to remove items. This will become more time consuming as the list or searchlists grow. And in your example there are duplicates in your searchlists.
Combining the searchlists will reduce number of comparisons.

Removing element messes up the index [duplicate]

This question already has answers here:
Loop "Forgets" to Remove Some Items [duplicate]
(10 answers)
Closed 8 years ago.
I have a simple question about lists
Suppose that I want to delete all 'a's from a list:
list = ['a', 'a', 'b', 'b', 'c', 'c']
for element in list:
if element == 'a':
list.remove('a')
print list
==> result:
['a', 'b', 'b', 'c', 'c', 'd', 'd']
I know this is happening because, after I remove the first 'a', the list index gets
incremented while all the elements get pushed left by 1.
In other languages, I guess one way to solve this is to iterate backwards from the end of the list..
However, iterating through reversed(list) returns the same error.
Is there a pythonic way to solve this problem??
Thanks
One of the more Pythonic ways:
>>> filter(lambda x: x != 'a', ['a', 'a', 'b', 'b', 'c', 'c'])
['b', 'b', 'c', 'c']
You should never modify a list while iterating over it.
A better approach would be to use a list comprehension to exclude an item:
list1 = ['a', 'a', 'b', 'b', 'c', 'c']
list2 = [x for x in list1 if x != 'a']
Note: Don't use list as a variable name in Python - it masks the built-in list type.
You are correct, when you remove an item from a list while iterating over it, the list index gets out of sync. What both the other existing answers are hinting at is that you need to create a new list and copy over only the items you want.
For example:
existing_list = ['a', 'a', 'b', 'c', 'd', 'e']
new_list = []
for element in existing_list:
if element != 'a':
new_list.append(element)
existing_list = new_list
print existing_list
outputs: ['b', 'c', 'd', 'e']

Categories