Understanding Python strip() with escape characters [duplicate] - python

Now I know that it is not safe to modify the list during an iterative looping. However, suppose I have a list of strings, and I want to strip the strings themselves. Does replacement of mutable values count as modification?
See Scope of python variable in for loop for a related problem: assigning to the iteration variable does not modify the underlying sequence, and also does not impact future iteration.

Since the loop below only modifies elements already seen, it would be considered acceptable:
a = ['a',' b', 'c ', ' d ']
for i, s in enumerate(a):
a[i] = s.strip()
print(a) # -> ['a', 'b', 'c', 'd']
Which is different from:
a[:] = [s.strip() for s in a]
in that it doesn't require the creation of a temporary list and an assignment of it to replace the original, although it does require more indexing operations.
Caution: Although you can modify entries this way, you can't change the number of items in the list without risking the chance of encountering problems.
Here's an example of what I mean—deleting an entry messes-up the indexing from that point on:
b = ['a', ' b', 'c ', ' d ']
for i, s in enumerate(b):
if s.strip() != b[i]: # leading or trailing whitespace?
del b[i]
print(b) # -> ['a', 'c '] # WRONG!
(The result is wrong because it didn't delete all the items it should have.)
Update
Since this is a fairly popular answer, here's how to effectively delete entries "in-place" (even though that's not exactly the question):
b = ['a',' b', 'c ', ' d ']
b[:] = [entry for entry in b if entry.strip() == entry]
print(b) # -> ['a'] # CORRECT
See How to remove items from a list while iterating?.

It's considered poor form. Use a list comprehension instead, with slice assignment if you need to retain existing references to the list.
a = [1, 3, 5]
b = a
a[:] = [x + 2 for x in a]
print(b)

One more for loop variant, looks cleaner to me than one with enumerate():
for idx in range(len(list)):
list[idx]=... # set a new value
# some other code which doesn't let you use a list comprehension

Modifying each element while iterating a list is fine, as long as you do not change add/remove elements to list.
You can use list comprehension:
l = ['a', ' list', 'of ', ' string ']
l = [item.strip() for item in l]
or just do the C-style for loop:
for index, item in enumerate(l):
l[index] = item.strip()

The answer given by Ignacio Vazquez-Abrams is really good. It can be further illustrated by this example. Imagine that:
A list with two vectors is given to you.
You would like to traverse the list and reverse the order of each one of the arrays.
Let's say you have:
v = np.array([1,2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i = i[::-1] # This command does not reverse the string.
print([v,b])
You will get:
[array([1, 2, 3, 4]), array([3, 4, 6])]
On the other hand, if you do:
v = np.array([1,2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i[:] = i[::-1] # This command reverses the string.
print([v,b])
The result is:
[array([4, 3, 2, 1]), array([6, 4, 3])]

No you wouldn't alter the "content" of the list, if you could mutate strings that way. But in Python they are not mutable. Any string operation returns a new string.
If you had a list of objects you knew were mutable, you could do this as long as you don't change the actual contents of the list.
Thus you will need to do a map of some sort. If you use a generator expression it [the operation] will be done as you iterate and you will save memory.

You can do something like this:
a = [1,2,3,4,5]
b = [i**2 for i in a]
It's called a list comprehension, to make it easier for you to loop inside a list.

It is not clear from your question what the criteria for deciding what strings to remove is, but if you have or can make a list of the strings that you want to remove , you could do the following:
my_strings = ['a','b','c','d','e']
undesirable_strings = ['b','d']
for undesirable_string in undesirable_strings:
for i in range(my_strings.count(undesirable_string)):
my_strings.remove(undesirable_string)
which changes my_strings to ['a', 'c', 'e']

In short, to do modification on the list while iterating the same list.
list[:] = ["Modify the list" for each_element in list "Condition Check"]
example:
list[:] = [list.remove(each_element) for each_element in list if each_element in ["data1", "data2"]]

Something I just discovered - when looping over a list of mutable types (such as dictionaries) you can just use a normal for loop like this:
l = [{"n": 1}, {"n": 2}]
for d in l:
d["n"] += 1
print(l)
# prints [{"n": 2}, {"n": 1}]

Related

How do I append values to make a multi-dimentional list?

My code:
list=[["Uno","Dos"],[1,2],["Tres","Cuatro"],[3,4]]
print(list)
list[4][0].insert(A)
New_list=[[],[],[],[]]
A=list[0][0]+str(list[1][0])
B=(list[0][0]+str(list[1][0]))[::-1]
C=list[0][1]+str(list[1][1])
D=(list[0][1]+str(list[1][1]))[::-1]
E=list[2][0]+str(list[3][0])
F=(list[2][0]+str(list[3][0]))[::-1]
G=list[2][1]+str(list[3][1])
H=(list[2][1]+str(list[3][1]))[::-1]
New_list[0][0].append(A)
print(New_list)
My expectation:
[["Uno1","1onU"],["Dos2","2soD"],["Tres3","3serT"],["Cuatro4","4ortauC"]]
I've tried to use append and insert but every time I get an error message; usually "list index is out of range"
How can I add my values to New_list?
append appends a value to your list inline. list[4][0] gives an error, because that value does not exist yet. With insert you can add entries to your list and specify the location as well where you want the entry to be insert, whereas append always attaches to the end of the list.
Example:
l = []
l.append("a")
print(l)
# ['a']
l.append(["b", "c"])
print(l)
# ['a', ['b', 'c']]
l.insert(0, "d")
print(l)
# ['d', 'a', ['b', 'c']]
Answering your question "How do I append values to make a multi-dimentional list?" You can append a list to a list, making it multi-dimensional. Small example:
my_list = []
my_list.append([1, 2, 3])
my_list.append([4, 5, 6])
my_list.append([7, 8, 9])
print(my_list)
# prints my_list (formatted nicely):
# [
# [1,2,3],
# [4,5,6],
# [7,8,9]
# ]
You are also trying to access out of bounds of your list on line 3, causing an error. Remember index starts at 0 for lists.
Use loops to perform similar operations through the list, rather than assigning separate variables for each list element.
old_list = [["Uno","Dos"],[1,2],["Tres","Cuatro"],[3,4]]
new_list = []
for i in range(0, len(old_list), 2):
num_strings = old_list[i]
nums = old_list[i+1]
for s, num in zip(num_strings, nums):
new_list.append([f'{s}{num}', f'{num}{s[::-1]}'])
print(new_list)
got something for you :
list=[["Uno","Dos"],[1,2],["Tres","Cuatro"],[3,4]]
A = list[0][0]+str(list[1][0])
reverse_A = A[::-1]
elemA = [A, reverse_A]
B = list[0][1]+str(list[1][1])
reverse_B = B[::-1]
elemB = [B, reverse_B]
C = list[2][0]+str(list[3][0])
reverse_C = C[::-1]
elemC = [C, reverse_C]
D = list[2][1]+str(list[3][1])
reverse_D = D[::-1]
elemD = [D, reverse_D]
new_list = [elemA, elemB, elemC, elemD]
print(new_list)
I think trying to do it by hand is little bit harder as when list grows.
U can wrap it inside a FOR loop as below:
for i in range(0,len(list),2):
str1=list[i][0]+str(list[i+1][0])
str2=list[i][1]+str(list[i+1][1])
New_list.append([str1,str1[::-1]])
New_list.append([str2,str2[::-1]])
This one can adapt to bigger lists automatically. I hope I've given you u the answer you were looking for
First, you cannot use list as an alias. Secondly, lists start numbering at 0, none of your lists have an element at list[4]. That would be a fifth element. Try this.
lista = [['Uno','Dos'],[1,2],['Tres','Cuatro'],[3,4]]
A = lista[0][0]+str(lista[1][0])
B = lista[0][1]+str(lista[1][1])
C = lista[2][0]+str(lista[3][0])
D = lista[2][1]+str(lista[3][1])
Lists = A, B, C, D
New_List = []
for lisx in Lists:
New_List.append((lisx, lisx[::-1]))

For Loop incrementing by 2s instead of 1 [duplicate]

Now I know that it is not safe to modify the list during an iterative looping. However, suppose I have a list of strings, and I want to strip the strings themselves. Does replacement of mutable values count as modification?
See Scope of python variable in for loop for a related problem: assigning to the iteration variable does not modify the underlying sequence, and also does not impact future iteration.
Since the loop below only modifies elements already seen, it would be considered acceptable:
a = ['a',' b', 'c ', ' d ']
for i, s in enumerate(a):
a[i] = s.strip()
print(a) # -> ['a', 'b', 'c', 'd']
Which is different from:
a[:] = [s.strip() for s in a]
in that it doesn't require the creation of a temporary list and an assignment of it to replace the original, although it does require more indexing operations.
Caution: Although you can modify entries this way, you can't change the number of items in the list without risking the chance of encountering problems.
Here's an example of what I mean—deleting an entry messes-up the indexing from that point on:
b = ['a', ' b', 'c ', ' d ']
for i, s in enumerate(b):
if s.strip() != b[i]: # leading or trailing whitespace?
del b[i]
print(b) # -> ['a', 'c '] # WRONG!
(The result is wrong because it didn't delete all the items it should have.)
Update
Since this is a fairly popular answer, here's how to effectively delete entries "in-place" (even though that's not exactly the question):
b = ['a',' b', 'c ', ' d ']
b[:] = [entry for entry in b if entry.strip() == entry]
print(b) # -> ['a'] # CORRECT
See How to remove items from a list while iterating?.
It's considered poor form. Use a list comprehension instead, with slice assignment if you need to retain existing references to the list.
a = [1, 3, 5]
b = a
a[:] = [x + 2 for x in a]
print(b)
One more for loop variant, looks cleaner to me than one with enumerate():
for idx in range(len(list)):
list[idx]=... # set a new value
# some other code which doesn't let you use a list comprehension
Modifying each element while iterating a list is fine, as long as you do not change add/remove elements to list.
You can use list comprehension:
l = ['a', ' list', 'of ', ' string ']
l = [item.strip() for item in l]
or just do the C-style for loop:
for index, item in enumerate(l):
l[index] = item.strip()
The answer given by Ignacio Vazquez-Abrams is really good. It can be further illustrated by this example. Imagine that:
A list with two vectors is given to you.
You would like to traverse the list and reverse the order of each one of the arrays.
Let's say you have:
v = np.array([1,2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i = i[::-1] # This command does not reverse the string.
print([v,b])
You will get:
[array([1, 2, 3, 4]), array([3, 4, 6])]
On the other hand, if you do:
v = np.array([1,2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i[:] = i[::-1] # This command reverses the string.
print([v,b])
The result is:
[array([4, 3, 2, 1]), array([6, 4, 3])]
No you wouldn't alter the "content" of the list, if you could mutate strings that way. But in Python they are not mutable. Any string operation returns a new string.
If you had a list of objects you knew were mutable, you could do this as long as you don't change the actual contents of the list.
Thus you will need to do a map of some sort. If you use a generator expression it [the operation] will be done as you iterate and you will save memory.
You can do something like this:
a = [1,2,3,4,5]
b = [i**2 for i in a]
It's called a list comprehension, to make it easier for you to loop inside a list.
It is not clear from your question what the criteria for deciding what strings to remove is, but if you have or can make a list of the strings that you want to remove , you could do the following:
my_strings = ['a','b','c','d','e']
undesirable_strings = ['b','d']
for undesirable_string in undesirable_strings:
for i in range(my_strings.count(undesirable_string)):
my_strings.remove(undesirable_string)
which changes my_strings to ['a', 'c', 'e']
In short, to do modification on the list while iterating the same list.
list[:] = ["Modify the list" for each_element in list "Condition Check"]
example:
list[:] = [list.remove(each_element) for each_element in list if each_element in ["data1", "data2"]]
Something I just discovered - when looping over a list of mutable types (such as dictionaries) you can just use a normal for loop like this:
l = [{"n": 1}, {"n": 2}]
for d in l:
d["n"] += 1
print(l)
# prints [{"n": 2}, {"n": 1}]

Iterating over lists of lists in Python

I have a list of lists:
lst1 = [["(a)", "(b)", "(c)"],["(d)", "(e)", "(f)", "(g)"]]
I want to iterate over each element and perform some string operations on them for example:
replace("(", "")
I tried iterating over the list using:
for l1 in lst1:
for i in l1:
lst2.append(list(map(str.replace("(", ""), l1)))
I wanted the out result to be the same as original list of lists but without the parenthesis. Also, I am looking for a method in editing lists of lists and not really a specific solution to this question.
Thank you,
Edit:
Yes, you should use normal for-loops if you want to:
Preform multiple operations on each item contained in each sub-list.
Keep both the main list as well as the sub-lists as the same objects.
Below is a simple demonstration of how to do this:
main = [["(a)", "(b)", "(c)"], ["(d)", "(e)", "(f)", "(g)"]]
print id(main)
print id(main[0])
print id(main[1])
print
for sub in main:
for index,item in enumerate(sub):
### Preform operations ###
item = item.replace("(", "")
item = item.replace(")", "")
item *= 2
sub[index] = item # Reassign the item
print main
print
print id(main)
print id(main[0])
print id(main[1])
Output:
25321880
25321600
25276288
[['aa', 'bb', 'cc'], ['dd', 'ee', 'ff', 'gg']]
25321880
25321600
25276288
Use a nested list comprehension:
>>> lst1 = [["(a)", "(b)", "(c)"],["(d)", "(e)", "(f)", "(g)"]]
>>> id(lst1)
35863808
>>> lst1[:] = [[y.replace("(", "") for y in x] for x in lst1]
>>> lst1
[['a)', 'b)', 'c)'], ['d)', 'e)', 'f)', 'g)']]
>>> id(lst1)
35863808
>>>
The [:] will keep the list object the same.
I just did what you did, i used the fact that each element of a list can be assigned a new (or updated) value:
>>> lst1 = [["(a)", "(b)", "(c)"],["(d)", "(e)", "(f)", "(g)"]]
>>> for x in range(len(lst1)):
for y in range(len(lst1[x])):
lst1[x][y] = lst1[x][y].replace("(", "")
>>> lst1
[['a)', 'b)', 'c)'], ['d)', 'e)', 'f)', 'g)']]
EDIT
This is how you do it with the "real problem" that you mentioned in the comment:
a = [[(12.22, 12.122, 0.000)], [(1232.11, 123.1231, 0.000)]]
some_num = 10
for x in range(len(a)):
b = list(a[x][0])
for y in range(len(b)):
b[y] *= some_num
a[x] = tuple(b)
print(a)
OUTPUT:
[(122.2, 121.22, 0.0), (12321.099999999999, 1231.231, 0.0)]
^ All elements have been multiplied by a number and the original format is kept
This is how it works:
So you have the initial list 'a' that has two sublists each with only ONE element (the tuple that contains the x,y,z coordinates). I go through list 'a' and make the tuples a list and set them equal to 'b' (so the fourth line has a value of [12.22, 12.122, 0.000] the first time around (and the next tuple (as a list) the next time around).
Then I go through each of the elements in 'b' (the tuple converted into a list) and multiply each element in that tuple by a number with the use of the increment operator (+=, -=, /=, *=). Once this loop is done, I set that same position in the master list 'a' equal to the tuple of the previously converted tuple. < If this doesn't make sense, what I'm saying is that the initial tuples are converted into lists (then operated on), and then converter back to tuples (since you want it to end up with the same format as before).
Hope this helps!
>>> lst1 = [["(a)", "(b)", "(c)"],["(d)", "(e)", "(f)", "(g)"]]
>>> [[j.strip('()') for j in i] for i in lst1]
[['a', 'b', 'c'], ['d', 'e', 'f', 'g']]
>>> [[j.lstrip('(') for j in i] for i in lst1]
[['a)', 'b)', 'c)'], ['d)', 'e)', 'f)', 'g)']]

How to remove a list within list based on len in python?

I have the following input list
A = [['A',[1,2,3]],['D',[3,4]],['E',[6,7]],['F',[1]]]
I want to have sublists whose length is 2.
In the above example, I want to remove [A,[1,2,3]], [F,[1]] etc
I am creating a new list and appending all sublists whose length ==2.
If I can directly remove from A, the unwanted sublists, it would be ideal
Should't it be like this?
A = [x for x in A if len(x[1]) == 2]
Or even
A = [[a, b] for a, b in A if len(b) == 2]
You might want to use filter.
filter(lambda x: len(x[1]) == 2, A)
This assumes each of the element (list) has 2 elements, and the second element is a list. You want to filter the elements which have exactly 2 elements in this inner list.
More on filter:
filter(...)
filter(function or None, sequence) -> list, tuple, or string
Return those items of sequence for which function(item) is true.
The same can be achieved via a list comprehension:
[x for x in A if len(x[1]) == 2]
It's better and easier to create a new filtered list. A[:] = ... is a slice assignment which means that the content of the new list is copied back into A so that other references to the same list will see the update. If you don't need to keep the identity of A, you can just use A = ...
>>> A = [['A',[1,2,3]],['D',[3,4]],['E',[6,7]],['F',[1]]]
>>> A[:] = [x for x in A if len(x[1]) == 2]
>>> A
[['D', [3, 4]], ['E', [6, 7]]]
Removing in place is usually inefficient because you need to move the remaining items down the list each time you remove one. You also need to take care to not skip over elements when you remove from the list you are iterating over.
A = [x if len(x)==2 for x in A]
fyi, your E and F lists don't have closing brackets, but I'm assuming that's just a copy/paste error or similar.

python removing whitespace from string in a list

I have a list of lists. I want to remove the leading and trailing spaces from them. The strip() method returns a copy of the string without leading and trailing spaces. Calling that method alone does not make the change. With this implementation, I am getting an 'array index out of bounds error'. It seems to me like there would be "an x" for exactly every list within the list (0-len(networks)-1) and "a y" for every string within those lists (0-len(networks[x]) aka i and j should map exactly to legal, indexes and not go out of bounds?
i = 0
j = 0
for x in networks:
for y in x:
networks[i][j] = y.strip()
j = j + 1
i = i + 1
You're forgetting to reset j to zero after iterating through the first list.
Which is one reason why you usually don't use explicit iteration in Python - let Python handle the iterating for you:
>>> networks = [[" kjhk ", "kjhk "], ["kjhkj ", " jkh"]]
>>> result = [[s.strip() for s in inner] for inner in networks]
>>> result
[['kjhk', 'kjhk'], ['kjhkj', 'jkh']]
You don't need to count i, j yourself, just enumerate, also looks like you do not increment i, as it is out of loop and j is not in inner most loop, that is why you have an error
for x in networks:
for i, y in enumerate(x):
x[i] = y.strip()
Also note you don't need to access networks but accessing 'x' and replacing value would work, as x already points to networks[index]
This generates a new list:
>>> x = ['a', 'b ', ' c ']
>>> map(str.strip, x)
['a', 'b', 'c']
>>>
Edit: No need to import string when you use the built-in type (str) instead.
So you have something like: [['a ', 'b', ' c'], [' d', 'e ']], and you want to generate [['a', 'b',' c'], ['d', 'e']]. You could do:
mylist = [['a ', 'b', ' c'], [' d', 'e ']]
mylist = [[x.strip() for x in y] for y in mylist]
The use of indexes with lists is generally not necessary, and changing a list while iterating though it can have multiple bad side effects.
c=[]
for i in networks:
d=[]
for v in i:
d.append(v.strip())
c.append(d)
A much cleaner version of cleaning list could be implemented using recursion. This will allow you to have a infinite amount of list inside of list all while keeping a very low complexity to your code.
Side note: This also puts in place safety checks to avoid data type issues with strip. This allows your list to contain ints, floats, and much more.
def clean_list(list_item):
if isinstance(list_item, list):
for index in range(len(list_item)):
if isinstance(list_item[index], list):
list_item[index] = clean_list(list_item[index])
if not isinstance(list_item[index], (int, tuple, float, list)):
list_item[index] = list_item[index].strip()
return list_item
Then just call the function with your list. All of the values will be cleaned inside of the list of list.
clean_list(networks)

Categories