2

What is the Pythonic/quick way to search for a partial string in an array and then remove that string from the array?
(I can do it with a simple loop and IF IN and rebuild two array in the loop, Asking if there is a Pythonic way/function to do this)

Example:

array = ['rule1','rule2','exception[type_a]','rule3','exception[type_b]']
res(,)=remove_exceptions(array,'exception')
print(res[0]) >>> ['rule1','rule2','rule3']
print(res[1]) >>> ['exception[type_a]','exception[type_b]']
Itay Moav -Malimovka
  • 52,579
  • 61
  • 190
  • 278
  • You want to just remove them or you want to extract them from your list? – Mazdak Aug 25 '16 at 17:11
  • Iterating over your list and creating two new lists in the loop suite is Pythonic. If the list elements are as you represented, you could make use of the [```str.startswith```](https://docs.python.org/3/library/stdtypes.html#str.startswith) method. – wwii Aug 25 '16 at 17:20
  • @Kasramvd either would work for me – Itay Moav -Malimovka Aug 25 '16 at 17:29
  • @ItayMoav-Malimovka Check out my answer. – Mazdak Aug 25 '16 at 17:35
  • @Kasramvd while this is what I currently (almost) use, my question was if there is a built in function/language construct (Pythonic way) to do it more efficiently (either less text/faster). – Itay Moav -Malimovka Aug 25 '16 at 17:37
  • @ItayMoav-Malimovka There is no built-in function which can does this job. – Mazdak Aug 25 '16 at 17:40

5 Answers5

2
>>> [x for x in array if 'exception' not in x]
['rule1', 'rule2', 'rule3']
>>> [x for x in array if 'exception' in x]
['exception[type_a]', 'exception[type_b]']

See also: Python: split a list based on a condition?

Community
  • 1
  • 1
kjaquier
  • 824
  • 4
  • 11
1

If you want to separate your items you can do it with one loop and by preserving the items in a dictionary:

>>> d = {}
>>> for i in array:
...     if 'exception' in i:
...         d.setdefault('exception', []).append(i)
...     else:
...         d.setdefault('other', []).append(i)
... 
>>> 
>>> d
{'exception': ['exception[type_a]', 'exception[type_b]'], 'other': ['rule1', 'rule2', 'rule3']}

You can access to separated items by calling the values of the dictionary:

>>> d.values()
[['exception[type_a]', 'exception[type_b]'], ['rule1', 'rule2', 'rule3']]
Mazdak
  • 105,000
  • 18
  • 159
  • 188
1

Seriously, just use a for loop, you're trying to create two lists so a single comprehension won't do (i.e the top solution so far iterates twice over the same list).

Create two lists and append to them conditionally:

l1 = list()
l2 = list()
for i in array:
    l1.append(i) if 'exception' in i else l2.append(i)

print(l1)
['exception[type_a]', 'exception[type_b]']
print(l2)
['rule1', 'rule2', 'rule3']
Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
  • 1
    "a single comprehension won't do" I feel like there must be a way to do this with co-routines and a couple of `deque`s, so that you only pass over the list once, but use the minimal possible additional memory. As against that, like you say, seriously just use a for loop. Especially when the desired result is two lists, just make two lists :-) – Steve Jessop Aug 25 '16 at 18:18
0

You may use in-built filter with lambda function to achieve this as:

>>> my_array = array = ['rule1','rule2','exception[type_a]','rule3','exception[type_b]']
>>> my_string = 'exception'
>>> filter(lambda x: my_string not in x, my_array)
['rule1', 'rule2', 'rule3']
Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
  • What makes this Pythonic? – wwii Aug 25 '16 at 17:17
  • It is Pythonic because of the usage of inbuilt functions that Python provides and perfectly suits the requirement. That says, there is no need to do list comprehension. Now my question to you: What makes it non Pythonic? – Moinuddin Quadri Aug 25 '16 at 17:19
  • Comprehensions are (arguably) more readable. See [http://stackoverflow.com/a/3013722/1936320](http://stackoverflow.com/a/3013722/1936320) – kjaquier Aug 25 '16 at 17:22
  • I was curious why this was pythonic or more pythonic than just iterating over the list with a for loop and testing the elements in order to separate them. – wwii Aug 25 '16 at 17:24
  • "Readable" itself means for newbies who do not know much about Python. Whereas `pythonic` means the usage of inbuilt Python's functionality to achieve the task, and that too in most efficient way. – Moinuddin Quadri Aug 25 '16 at 17:26
  • I meant Pythonic in the same sense @MoinuddinQuadri meant – Itay Moav -Malimovka Aug 25 '16 at 17:27
  • ```...too in most efficient way...``` have you tested this against a simple for loop iteration? – wwii Aug 25 '16 at 17:27
  • There are many scenarios in which you can not use `filter` and must use `list comprehension` instead. But where you can use this, you must use it. – Moinuddin Quadri Aug 25 '16 at 17:27
  • Pythonic is more than just using builtin functions, it includes being readable (see `python -c "import this"`). Although I agree "readable" is subjective, who said that you **must** use builtin functions over native syntax whenever you can? – kjaquier Aug 25 '16 at 17:29
  • @wwii: I agree `comprehensions` are comparatively faster than `filter` but time difference is of miliseconds which can be ignored. I still feel to use the inbuilt function whereever you can else what is the point of those. – Moinuddin Quadri Aug 25 '16 at 17:49
  • @kjaquier: It is totally dependent on one's personal preference. I feel it should be used, even though it is not mandate to any one else. – Moinuddin Quadri Aug 25 '16 at 17:51
  • I think this debate is more regarding my mention of `more pythonic` way. Removed that. :) – Moinuddin Quadri Aug 25 '16 at 17:52
  • Specifically, the combination of `filter` with `lambda` is expressly non-Pythonic in the limited sense that [GvR has always hated it](http://www.artima.com/weblogs/viewpost.jsp?thread=98196). In my opinion `filter` is quite good when passed a function by name, and `filter(foo, things)` can read much better than `[thing for thing in things if foo(thing)]`. At least you don't have to choose a pointless loop variable name to type three times. But combined with a lambda most of that benefit's gone because you need to mention `thing` twice: `filter(lambda thing: something_about_thing, things)`. – Steve Jessop Aug 25 '16 at 18:27
  • 1
    In an ideal world you'd write `filter(not x.contains, my_array)`, but they're not offering us that ;-) – Steve Jessop Aug 25 '16 at 18:32
0

For list-of-strings array and thing-to-exclude target:

List comprehensions work:

result = [s for s in array if target not in s]

Or a generator comprehension for the same:

result = (s for s in array if target not in s)

(in is effectively a contains operator, and not in is the inverse.)

Alternately, use the filter() built-in with a lambda:

result = filter(lambda x: target not in x,
                array)

Either one returns a new object, rather than modifying your original list. The list comprehension returns a list, filter() returns a generator but you can wrap the call in list() if you need random access.

Vivian
  • 1,539
  • 14
  • 38