¿Cuál es la forma más rápida de buscar si una cadena contiene otra cadena basada en una lista?
Este funciona bien, pero es demasiado lento para mí cuando la cadena es grande y la lista es larga.
test_string = "Hello! This is a test. I love to eat apples."
fruits = ['apples', 'oranges', 'bananas']
for fruit in fruits:
if fruit in test_string:
print(fruit+" contains in the string")
6 respuestas
Para esto, sugeriría primero tokenizar la cadena con RegexpTokenizer
para eliminar todos los caracteres especiales y luego use sets
para encontrar la intersección:
from nltk.tokenize import RegexpTokenizer
test_string = "Hello! This is a test. I love to eat apples."
tokenizer = RegexpTokenizer(r'\w+')
test_set = set(tokenizer.tokenize(test_string))
# {'Hello', 'I', 'This', 'a', 'apples', 'eat', 'is', 'love', 'test', 'to'}
Habiendo tokenizado la cadena y construido un conjunto, encuentre el set.intersection
:
set(['apples', 'oranges', 'bananas']) & test_set
# {'apples'}
Los conjuntos son probablemente su mejor apuesta para la velocidad cuando se utiliza el operador in
.
Para construir un conjunto que contenga solo palabras, necesitamos:
1) eliminar la puntuación de la cadena;
2) divide la cadena en espacios en blanco.
Para eliminar la puntuación, esta respuesta probablemente tenga la solución más rápida ( usando str.makestrans
y string.punctuation
).
Aquí hay un ejemplo usando su caso de prueba:
import string
test_string = "Hello! This is a test. I love to eat apples."
test_string_no_punctuation = test_string.translate(str.maketrans('', '', string.punctuation))
word_set = set(test_string_no_punctuation.split())
fruits = ['apples', 'oranges', 'bananas']
for fruit in fruits:
if fruit in word_set:
print(fruit+" contains in the string")
Es posible que desee ajustar las operaciones detalladas de eliminar signos de puntuación + dividir la cadena en una función:
def word_set(input_string):
return set(input_string.translate(str.maketrans('', '', string.punctuation)).split())
El texto suele ser más grande que la lista de palabras que está buscando.
for fruit in fruits:
if fruit in test_string:
print(fruit+" contains in the string")
Esto es realmente ineficiente porque en realidad está recorriendo todo el texto de cada fruta en la lista de frutas, puede que no sea un problema para las oraciones cortas, pero si estaba buscando textos largos, este proceso tomaría mucho más tiempo.
Una mejor manera es iterar a través del texto una vez y atrapar todas las palabras que están en la lista de frutas en el camino.
Podrías hacer algo como esto:
import re
fruits = ['apples', 'oranges', 'bananas']
test_string = "Hello! This is a test. I love to eat apples."
basket = set(fruits)
words = re.compile('\w+')
for match in words.finditer(test_string):
fruit = match.group()
if fruit in basket:
print(fruit + " contains in the string")
Salida
apples contains in the string
Si solo le interesa si hay una palabra presente:
>>> words = set(test_string.replace('.',' ').lower().split())
>>> any(fruit in words for fruit in fruits)
True
Por supuesto, puede recorrer cada fruta para verificar cuáles se pueden encontrar en el pastel de frutas. Por lo tanto, cambiaría if fruit in test_string
a if fruit in words
en su ejemplo de bucle.
Si. puedes disminuir tus iteraciones de esta manera:
print(any(fruit in frozenset(test_string.replace('.',' ').lower().split()) for fruit in fruits))
Preguntas relacionadas
Preguntas vinculadas
Nuevas preguntas
python
Python es un lenguaje de programación multipropósito, de tipificación dinámica y de múltiples paradigmas. Está diseñado para ser rápido de aprender, comprender y usar, y hacer cumplir una sintaxis limpia y uniforme. Tenga en cuenta que Python 2 está oficialmente fuera de soporte a partir del 01-01-2020. Aún así, para preguntas de Python específicas de la versión, agregue la etiqueta [python-2.7] o [python-3.x]. Cuando utilice una variante de Python (por ejemplo, Jython, PyPy) o una biblioteca (por ejemplo, Pandas y NumPy), inclúyala en las etiquetas.