Deleting list from a list of lists - python

I need to delete these lists inside of list that contains the / symbol.
List for example:
X = [['a/','$1'], ["c","d"]]
so X[0] should be deleted. The actual list are much longer and contains more instances of this condition.
I tried use something like:
print([l for l in X if l.count("/") <1])
But if I understand correctly because the / is attached to another symbol he is not counted.
Should I convert this list of lists to string, separate the / from another character, and then use the count function, or there is better solution?

One way to search "/" in each item in the sublists is to wrap a generator expression with any. Since you don't want sublists with "/" in it, the condition should be not any():
out = [lst for lst in X if not any('/' in x for x in lst)]
Output:
[['c', 'd']]

The call to filter() applies that lambda function to every list in X and filters out list with '/'.
result = list(filter(lambda l: not any('/' in s for s in l), X))

counter = 0
while counter < len(X):
removed = False
for i in X[counter]:
if '/' in i:
X.pop(counter)
removed = True
break
if not removed:
counter += 1

Given:
X = [['a/','$1'], ["c","d"]]
You can convert the sub lists to their repr string representations and detect the / in that string:
new_x=[sl for sl in X if not '/' in repr(sl)]
Or, you can use next:
new_x=[sl for sl in X if not next('/' in s for s in sl)]
Either:
>>> new_x
[['c', 'd']]

Related

How delete a element of a list and save the original index of deleted element?

I want delete some elements of one list equal to a value:
I can do it :
List =[1,2,3.....]
List = [x for x in List if x != 2]
How can i save the indexs of the deleted elements ?
I want to use this index to delete elements of another list.
Simplest solution is to make a list of indices to keep, then use that to strip the elements from both of your lists. itertools provides a handy compress utility to apply the indices to keep quickly:
from itertools import compress
tokeep = [x != 2 for x in List]
List = list(compress(List, tokeep))
otherlist = list(compress(otherlist, tokeep))
Alternatively (and frankly more clearly) you can just use one loop to strip both inputs; listcomps are fun, but sometimes they're not the way to go.
newlist = []
newotherlist = []
for x, y in zip(List, otherlist):
if x != 2:
newlist.append(x)
newotherlist.append(y)
which gets the same effect in a single pass. Even if it does feel less overtly clever, it's very clear, which is a good thing; brevity for the sake of brevity that creates complexity is not a win.
And now, to contradict that last paragraph, the amusingly overtly clever and brief solution to one-line this:
List, otherlist = map(list, zip(*[(x, y) for x, y in zip(List, otherlist) if x != 2]))
For the love of sanity, please don't actually use this, I just had to write it for funsies.
You can also leverage enumerate
for index, val in enumerate(List):
if val == value:
del List[index]
break
print(index)
Based on documentation
list_first = ['d', 'a']
list_second = ['x', 'z']
def remove_from_lists(element):
index_deleted = list_first.index(element)
list_first.remove(element)
list_second.pop(index_deleted)
remove_from_lists('d')

How to remove matching item from nested list?

I have a list with lists and I would like remove a wildcard matching item from each list if present, otherwise return it as it is.
Example
nested_list = [["abc","fds","gfssdf"],["dfsdf","cds","dvc"],["dsaf","abcvs","ewq"],...]
What I tried to do is:
for x in nested_list :
for y in x:
if re.search('abc.+', y) in x:
nested_list.remove(x)
However it returns the same list, without any changes
My desirable output would be:
nested_list = [["fds","gfssdf"],["dfsdf","cds","dvc"],["dsaf","ewq"],...]
Is there a solution?
Here is one way to do this with a nested 2D list comprehension:
nested_list = [["abc","fds","gfssdf"],["dfsdf","cds","dvc"],["dsaf","abcvs","ewq"]]
output = [[y for y in x if not re.search(r'^abc', y)] for x in nested_list]
print(output) # [['fds', 'gfssdf'], ['dfsdf', 'cds', 'dvc'], ['dsaf', 'ewq']]
You could also do this using startswith instead of re:
>>> [[y for y in x if not y.startswith("abc")] for x in nested_list]
[['fds', 'gfssdf'], ['dfsdf', 'cds', 'dvc'], ['dsaf', 'ewq']]
The other answers are providing a nice solution, but I wanted to answer OP's original question for learning purposes
There are some mistakes in your code, I'll adress them one by one:
if re.search('abc.+', y) in x:
re.search returns None if it's not found, so you can remove the in x
The + in abc.+ searched for 1 or more, since you want to match abc, change the + to a ? to match 0 or more
If you'd remove all the elements from an deeper list, you'll end op with a empty list, so lets add a check for that and remove the empty list:
if not x:
nested_list.remove(x)
Applying those fixes gives us:
import re
nested_list = [["abc","fds","gfssdf"],["dfsdf","cds","dvc"],["dsaf","abcvs","ewq"], ["abc"]]
for x in nested_list :
for y in x:
if re.search('abc.?', y):
x.remove(y)
if not x:
nested_list.remove(x)
print(nested_list)
Witch gives the expected output:
[['fds', 'gfssdf'], ['dfsdf', 'cds', 'dvc'], ['dsaf', 'ewq']]
As you can test in this online demo.

Reverse strings in a nested list without slicing or reversed

In python if my list is
TheTextImage = [["111000"],["222999"]]
How would one loop through this list creating a new one of
NewTextImage = [["000111"],["999222"]]
Can use [:] but not [::-1], and cannot use reverse()
You know how to copy a sequence to another sequence one by one, right?
new_string = ''
for ch in old_string:
new_string = new_string + ch
If you want to copy the sequence in reverse, just add the new values onto the left instead of onto the right:
new_string = ''
for ch in old_string:
new_string = ch + new_string
That's really the only trick you need.
Now, this isn't super-efficient, because string concatenation takes quadratic time. You could solve this by using a collections.deque (which you can append to the left of in constant time) and then calling ''.join at the end. But I doubt your teacher is expecting that from you. Just do it the simple way.
Of course you have to loop over TextImage applying this to every string in every sublist in the list. That's probably what they're expecting you to use [:] for. But that's easy; it's just looping over lists.
You may not use [::-1] but you can multiply each range index by -1.
t = [["111000"],["222999"]]
def rev(x):
return "".join(x[(i+1)*-1] for i in range(len(x)))
>>> [[rev(x) for x in z] for z in t]
[['000111'], ['999222']]
If you may use the step arg in range, can do AChampions suggestion:
def rev(x):
return ''.join(x[i-1] for i in range(0, -len(x), -1))
If you can't use any standard functionality such as reversed or [::-1], you can use collections.deque and deque.appendleft in a loop. Then use a list comprehension to apply the logic to multiple items.
from collections import deque
L = [["111000"], ["222999"]]
def reverser(x):
out = deque()
for i in x:
out.appendleft(i)
return ''.join(out)
res = [[reverser(x[0])] for x in L]
print(res)
[['000111'], ['999222']]
Note you could use a list, but appending to the beginning of a list is inefficient.
You can use reduce(lambda x,y: y+x, string) to reverse a string
>>> from functools import reduce
>>> TheTextImage = [["111000"],["222999"]]
>>> [[reduce(lambda x,y: y+x, b) for b in a] for a in TheTextImage]
[['000111'], ['999222']]

How to remove characters from each element in a list

I would like to remove the first two characters from each element (which are currently ints) that i have in a list. This is what i have:
lst = [2011,2012,3013]
I would like to get this
lst= [11,12,13]
I do not want a solution with some sort of replace 20 or 30 with '' however.
Given source= [2011,-2012,-3013] :
Result as ints, unsigned:
dest = [abs(x)%100 for x in source]
Result as ints, signed
dest = [(abs(x)%100)*(1 if x > 0 else -1) for x in source]
Result as strings, unsigned (preserves leading zeroes):
dest = list(map(lambda x : str(x)[-2:],source)
Result as strings, signed (preserves leading zeroes):
dest = list(map(lambda x : ("-" if str(x)[0]=="-" else "")+str(x)[-2:],source))
You can use:
list = [abs(number)%100 for number in list]
And it's a bad practice to name lists list. Use another name.
You can use module by 100,like:
my_list= [2011,2012,3013]
expected_list = [i%100 for i in my_list]
If you have negative numbers in my_list:
expected_list=[abs(i)%100 for i in my_list]
Or use string slicing:
expected_list = [int(str(i)[2:]) for i in my_list] #[2:],because you want to remove first two numbers
Please try avoid using reserved keywords as you variable name, as you have used list as your variable name.
Modulo:
just modulo each element with like 100
list= [2011,2012,3013]
for i in range(len(list)):
list[i] %= 100

Extract substrings from a list into a list in Python

I have a Python list like:
['user#gmail.com', 'someone#hotmail.com'...]
And I want to extract only the strings after # into another list directly, such as:
mylist = ['gmail.com', 'hotmail.com'...]
Is it possible? split() doesn't seem to be working with lists.
This is my try:
for x in range(len(mylist)):
mylist[x].split("#",1)[1]
But it didn't give me a list of the output.
You're close, try these small tweaks:
Lists are iterables, which means its easier to use for-loops than you think:
for x in mylist:
#do something
Now, the thing you want to do is 1) split x at '#' and 2) add the result to another list.
#In order to add to another list you need to make another list
newlist = []
for x in mylist:
split_results = x.split('#')
# Now you have a tuple of the results of your split
# add the second item to the new list
newlist.append(split_results[1])
Once you understand that well, you can get fancy and use list comprehension:
newlist = [x.split('#')[1] for x in mylist]
That's my solution with nested for loops:
myl = ['user#gmail.com', 'someone#hotmail.com'...]
results = []
for element in myl:
for x in element:
if x == '#':
x = element.index('#')
results.append(element[x+1:])

Categories