Tengo una lista con cadenas como la siguiente.
candidates = ["Hello", "World", "HelloWorld", "Foo", "bar", "ar"] Y quiero que la lista se filtre como ["HelloWorld", "Foo", "Bar"] , porque otras son subcadenas. Puedo hacerlo así, pero no creas que es rápido o elegante.
def filter_not_substring(candidates): survive = [] for a in candidates: for b in candidates: if a == b: continue if a in b: break else: survive.append(a) return survive¿Hay alguna forma rápida de hacerlo?
Qué tal si:
candidates = ["Hello", "World", "HelloWorld", "Foo", "bar", "ar"] result = [c for c in candidates if not any(c in o and len(o) > len(c) for o in candidates)] print(result)En contra de lo que se sugirió en los comentarios:
from timeit import timeit def filter_not_substring(candidates): survive = [] for a in candidates: for b in candidates: if a == b: continue if a in b: break else: survive.append(a) return survive def filter_not_substring2a(candidates): return [c for c in candidates if not any(len(o) > len(c) and c in o for o in candidates)] def filter_not_substring2b(candidates): return [c for c in candidates if not any(c in o and len(o) > len(c) for o in candidates)] xs = ["Hello", "World", "HelloWorld", "Foo", "bar", "ar", "bar"] print(filter_not_substring(xs), filter_not_substring2a(xs), filter_not_substring2b(xs)) print(timeit(lambda: filter_not_substring(xs))) print(timeit(lambda: filter_not_substring2a(xs))) print(timeit(lambda: filter_not_substring2b(xs)))Resultado:
['HelloWorld', 'Foo', 'bar', 'bar'] ['HelloWorld', 'Foo', 'bar', 'bar'] ['HelloWorld', 'Foo', 'bar', 'bar'] 1.5163685 4.6516653 3.8334089999999996 Entonces, la solución de OP es sustancialmente más rápida, pero filter_not_substring2b sigue siendo un 20% más rápido que 2a . Por lo tanto, poner la comparación de len primero no ahorra tiempo.
Para cualquier escenario de producción, la función de OP es probablemente óptima: una forma de acelerarla podría ser llevar todo el problema a C, pero dudo que muestre grandes ganancias, ya que la lógica ya es bastante sencilla y espero que Python lo haga. hacer un trabajo bastante bueno también.
El usuario @ming señaló que la solución de OP se puede mejorar un poco:
def filter_not_substring_b(candidates): survive = [] for a in candidates: for b in candidates: if a in b and a != b: break else: survive.append(a) return surviveEsta versión de la función es algo más rápida, para mí un 10-15%
Finalmente, tenga en cuenta que esto es solo un poco más rápido que 2b , aunque es muy similar a la solución optimizada de @ming, pero casi 3 veces más lento que su solución. No me queda claro por qué sería eso; si alguien tiene una opinión bastante segura al respecto, por favor comparta en los comentarios:
def filter_not_substring_c(candidates): return [a for a in candidates if all(a not in b or a == b for b in candidates)]