¿Cómo convertir una lista de Python en un conjunto (set) preservando el orden original?

PythonBeginner
Practicar Ahora

Introducción

Las estructuras de datos integradas de Python ofrecen formas flexibles de gestionar y manipular datos. En este tutorial, exploraremos cómo convertir una lista de Python en un conjunto (set) preservando el orden original de los elementos. Esta técnica es particularmente útil cuando necesita eliminar duplicados de una lista pero mantener el orden de la primera aparición de cada elemento único.

Al final de este tutorial, comprenderá las diferencias entre listas y conjuntos en Python y aprenderá múltiples técnicas para convertir una lista en un conjunto manteniendo el orden original de los elementos.

Comprender Listas y Conjuntos (Sets) en Python

Antes de sumergirnos en la conversión de listas a conjuntos, comprendamos las propiedades básicas de estas dos estructuras de datos en Python.

Listas en Python

Las listas en Python son colecciones ordenadas que pueden almacenar elementos de diferentes tipos de datos. Permiten valores duplicados y mantienen el orden de inserción de los elementos.

Creemos un archivo Python simple para demostrar las listas. Abra el editor de código y cree un nuevo archivo llamado list_demo.py en el directorio /home/labex/project:

## Listas en Python
my_list = [1, 2, 3, 2, 4, 5, 3]

print("Lista original:", my_list)
print("Longitud de la lista:", len(my_list))
print("Primer elemento:", my_list[0])
print("Último elemento:", my_list[-1])
print("Primeros 3 elementos:", my_list[:3])
print("¿Contiene la lista duplicados?", len(my_list) != len(set(my_list)))

Ahora ejecute este archivo en la terminal:

python3 list_demo.py

Debería ver una salida similar a esta:

Lista original: [1, 2, 3, 2, 4, 5, 3]
Longitud de la lista: 7
Primer elemento: 1
Último elemento: 3
Primeros 3 elementos: [1, 2, 3]
¿Contiene la lista duplicados? True

Conjuntos (Sets) en Python

Los conjuntos (sets) son colecciones desordenadas de elementos únicos. Cuando convierte una lista en un conjunto, los elementos duplicados se eliminan automáticamente, pero el orden original no se conserva.

Creemos otro archivo llamado set_demo.py para explorar los conjuntos:

## Conjuntos en Python
my_list = [1, 2, 3, 2, 4, 5, 3]
my_set = set(my_list)

print("Lista original:", my_list)
print("Convertido a conjunto:", my_set)
print("Longitud de la lista:", len(my_list))
print("Longitud del conjunto:", len(my_set))
print("¿Mantiene el conjunto el orden?", list(my_set) == [1, 2, 3, 4, 5])

Ejecute este archivo:

python3 set_demo.py

La salida mostrará:

Lista original: [1, 2, 3, 2, 4, 5, 3]
Convertido a conjunto: {1, 2, 3, 4, 5}
Longitud de la lista: 7
Longitud del conjunto: 5
¿Mantiene el conjunto el orden? False

Observe que el conjunto eliminó todos los duplicados, pero el orden podría ser diferente al de la lista original. Esto se debe a que los conjuntos en Python son inherentemente desordenados.

Enfoque Básico: Convertir una Lista en un Conjunto (Set)

Ahora que entendemos las diferencias entre listas y conjuntos, exploremos cómo convertir una lista en un conjunto y las implicaciones de esta conversión.

Conversión Simple

La forma más básica de convertir una lista en un conjunto es utilizando la función integrada set(). Cree un nuevo archivo llamado basic_conversion.py:

## Conversión básica de lista a conjunto
fruits = ["apple", "banana", "orange", "apple", "pear", "banana"]

## Convertir lista a conjunto (elimina duplicados pero pierde el orden)
unique_fruits = set(fruits)

print("Lista original:", fruits)
print("Como conjunto:", unique_fruits)

## Convertir de nuevo a lista (el orden no se conserva)
unique_fruits_list = list(unique_fruits)
print("De vuelta a lista:", unique_fruits_list)

Ejecute este archivo:

python3 basic_conversion.py

Debería ver una salida similar a:

Lista original: ['apple', 'banana', 'orange', 'apple', 'pear', 'banana']
Como conjunto: {'orange', 'banana', 'apple', 'pear'}
De vuelta a lista: ['orange', 'banana', 'apple', 'pear']

Observe que el conjunto eliminó todos los duplicados, pero el orden es diferente al de la lista original. Cuando convertimos el conjunto de nuevo a una lista, el orden sigue sin ser el mismo que en nuestra lista original.

El Problema con el Orden

Esta conversión simple demuestra el problema que estamos tratando de resolver: cuando convertimos una lista en un conjunto, perdemos el orden original de los elementos. Si el orden original es importante, este enfoque no es adecuado.

Modifiquemos nuestro ejemplo para mostrar por qué esto podría ser un problema. Cree un archivo llamado order_matters.py:

## Ejemplo que muestra por qué el orden importa
steps = ["Preheat oven", "Mix ingredients", "Pour batter", "Bake", "Mix ingredients"]

## Eliminar duplicados usando set
unique_steps = list(set(steps))

print("Pasos de cocina originales:", steps)
print("Pasos únicos (usando set):", unique_steps)
print("¿Se conserva el orden?", unique_steps == ["Preheat oven", "Mix ingredients", "Pour batter", "Bake"])

Ejecute el archivo:

python3 order_matters.py

La salida será:

Pasos de cocina originales: ['Preheat oven', 'Mix ingredients', 'Pour batter', 'Bake', 'Mix ingredients']
Pasos únicos (usando set): ['Preheat oven', 'Bake', 'Mix ingredients', 'Pour batter']
¿Se conserva el orden? False

En este ejemplo, el orden de los pasos de cocina es crítico. Si hornea antes de mezclar los ingredientes, el resultado será desastroso. Esto ilustra por qué necesitamos una forma de preservar el orden original al eliminar duplicados.

Preservando el Orden al Convertir una Lista en un Conjunto (Set)

Ahora que entendemos el problema, exploremos métodos para convertir una lista en un conjunto preservando el orden original de los elementos.

Método 1: Usando un Diccionario para Preservar el Orden

Un enfoque es usar un diccionario para realizar un seguimiento del orden de los elementos. Desde Python 3.7, los diccionarios mantienen el orden de inserción por defecto.

Cree un nuevo archivo llamado dict_approach.py:

## Usando un diccionario para preservar el orden
fruits = ["apple", "banana", "orange", "apple", "pear", "banana"]

## Crear un diccionario con los elementos de la lista como claves
## Esto elimina automáticamente los duplicados mientras se preserva el orden
unique_fruits_dict = dict.fromkeys(fruits)

## Convertir las claves del diccionario de nuevo a una lista
unique_fruits = list(unique_fruits_dict)

print("Lista original:", fruits)
print("Elementos únicos (orden preservado):", unique_fruits)

Ejecute el archivo:

python3 dict_approach.py

Debería ver:

Lista original: ['apple', 'banana', 'orange', 'apple', 'pear', 'banana']
Elementos únicos (orden preservado): ['apple', 'banana', 'orange', 'pear']

Observe que se preserva el orden de la primera aparición de cada elemento.

Método 2: Usando OrderedDict

Para los usuarios de versiones de Python anteriores a 3.7, o para hacer la intención más explícita, podemos usar OrderedDict del módulo collections.

Cree un nuevo archivo llamado ordered_dict_approach.py:

## Usando OrderedDict para preservar el orden
from collections import OrderedDict

fruits = ["apple", "banana", "orange", "apple", "pear", "banana"]

## Crear un OrderedDict con los elementos de la lista como claves
## Esto elimina automáticamente los duplicados mientras se preserva el orden
unique_fruits_ordered = list(OrderedDict.fromkeys(fruits))

print("Lista original:", fruits)
print("Elementos únicos (orden preservado):", unique_fruits_ordered)

Ejecute el archivo:

python3 ordered_dict_approach.py

La salida debería ser:

Lista original: ['apple', 'banana', 'orange', 'apple', 'pear', 'banana']
Elementos únicos (orden preservado): ['apple', 'banana', 'orange', 'pear']

Método 3: Usando un Bucle y un Conjunto (Set) para Comprobar

Otro enfoque es usar un bucle y un conjunto para verificar si hemos visto un elemento antes.

Cree un nuevo archivo llamado loop_approach.py:

## Usando un bucle y un conjunto para preservar el orden
fruits = ["apple", "banana", "orange", "apple", "pear", "banana"]

unique_fruits = []
seen = set()

for fruit in fruits:
    if fruit not in seen:
        seen.add(fruit)
        unique_fruits.append(fruit)

print("Lista original:", fruits)
print("Elementos únicos (orden preservado):", unique_fruits)

Ejecute el archivo:

python3 loop_approach.py

La salida debería ser:

Lista original: ['apple', 'banana', 'orange', 'apple', 'pear', 'banana']
Elementos únicos (orden preservado): ['apple', 'banana', 'orange', 'pear']

Los tres métodos logran el mismo resultado: eliminar duplicados mientras se preserva el orden de la primera aparición de cada elemento.

Ejemplo Práctico: Análisis de Datos de Texto

Apliquemos lo que hemos aprendido a un ejemplo del mundo real: analizar la frecuencia de palabras en un texto mientras se preserva el orden de la primera aparición.

Creación de una Herramienta de Análisis de Texto

Cree un nuevo archivo llamado text_analyzer.py:

def analyze_text(text):
    """
    Analiza el texto para encontrar palabras únicas en orden de primera aparición
    y sus frecuencias.
    """
    ## Divide el texto en palabras y convierte a minúsculas
    words = text.lower().split()

    ## Elimina la puntuación de las palabras
    clean_words = [word.strip('.,!?:;()[]{}""\'') for word in words]

    ## Cuenta la frecuencia mientras se preserva el orden
    word_counts = {}
    unique_words_in_order = []

    for word in clean_words:
        if word and word not in word_counts:
            unique_words_in_order.append(word)
        word_counts[word] = word_counts.get(word, 0) + 1

    return unique_words_in_order, word_counts

## Texto de ejemplo
sample_text = """
Python is amazing. Python is also easy to learn.
With Python, you can create web applications, data analysis tools,
machine learning models, and much more. Python has many libraries
that make development faster. Python is versatile!
"""

## Analiza el texto
unique_words, word_frequencies = analyze_text(sample_text)

## Imprime los resultados
print("Ejemplo de texto:")
print(sample_text)
print("\nPalabras únicas en orden de primera aparición:")
print(unique_words)
print("\nFrecuencias de palabras:")
for word in unique_words:
    if word:  ## Omite cadenas vacías
        print(f"'{word}': {word_frequencies[word]} veces")

Ejecute el archivo:

python3 text_analyzer.py

La salida mostrará las palabras únicas en el orden en que aparecieron por primera vez en el texto, junto con sus frecuencias:

Ejemplo de texto:

Python is amazing. Python is also easy to learn.
With Python, you can create web applications, data analysis tools,
machine learning models, and much more. Python has many libraries
that make development faster. Python is versatile!

Palabras únicas en orden de primera aparición:
['python', 'is', 'amazing', 'also', 'easy', 'to', 'learn', 'with', 'you', 'can', 'create', 'web', 'applications', 'data', 'analysis', 'tools', 'machine', 'learning', 'models', 'and', 'much', 'more', 'has', 'many', 'libraries', 'that', 'make', 'development', 'faster', 'versatile']

Frecuencias de palabras:
'python': 5 veces
'is': 3 veces
'amazing': 1 veces
'also': 1 veces
...

Mejorando la Herramienta

Mejoremos nuestro analizador de texto para manejar escenarios más complejos. Cree un archivo llamado improved_analyzer.py:

from collections import OrderedDict

def analyze_text_improved(text):
    """
    Una versión mejorada del analizador de texto que maneja escenarios más complejos
    y proporciona más estadísticas.
    """
    ## Divide el texto en palabras y convierte a minúsculas
    words = text.lower().split()

    ## Elimina la puntuación de las palabras
    clean_words = [word.strip('.,!?:;()[]{}""\'') for word in words]

    ## Usa OrderedDict para preservar el orden y contar la frecuencia
    word_counts = OrderedDict()

    for word in clean_words:
        if word:  ## Omite cadenas vacías
            word_counts[word] = word_counts.get(word, 0) + 1

    ## Obtiene estadísticas
    total_words = sum(word_counts.values())
    unique_words_count = len(word_counts)

    return list(word_counts.keys()), word_counts, total_words, unique_words_count

## Texto de ejemplo
sample_text = """
Python is amazing. Python is also easy to learn.
With Python, you can create web applications, data analysis tools,
machine learning models, and much more. Python has many libraries
that make development faster. Python is versatile!
"""

## Analiza el texto
unique_words, word_frequencies, total_count, unique_count = analyze_text_improved(sample_text)

## Imprime los resultados
print("Ejemplo de texto:")
print(sample_text)
print("\nEstadísticas:")
print(f"Total de palabras: {total_count}")
print(f"Palabras únicas: {unique_count}")
print(f"Ratio de unicidad: {unique_count/total_count:.2%}")

print("\nLas 5 palabras más frecuentes:")
sorted_words = sorted(word_frequencies.items(), key=lambda x: x[1], reverse=True)
for word, count in sorted_words[:5]:
    print(f"'{word}': {count} veces")

Ejecute el archivo:

python3 improved_analyzer.py

Debería ver una salida con estadísticas adicionales:

Ejemplo de texto:

Python is amazing. Python is also easy to learn.
With Python, you can create web applications, data analysis tools,
machine learning models, and much more. Python has many libraries
that make development faster. Python is versatile!

Estadísticas:
Total de palabras: 38
Palabras únicas: 30
Ratio de unicidad: 78.95%

Las 5 palabras más frecuentes:
'python': 5 veces
'is': 3 veces
'to': 1 veces
'learn': 1 veces
'with': 1 veces

Este ejemplo práctico demuestra cómo preservar el orden de los elementos al eliminar duplicados puede ser útil en aplicaciones del mundo real como el análisis de texto.

Comparación de Rendimiento y Mejores Prácticas

Ahora que hemos explorado varios métodos para convertir una lista en un conjunto (set) preservando el orden, comparemos su rendimiento y establezcamos algunas mejores prácticas.

Creación de una Prueba de Rendimiento

Cree un nuevo archivo llamado performance_test.py:

import time
from collections import OrderedDict

def method1_dict(data):
    """Using dict.fromkeys()"""
    return list(dict.fromkeys(data))

def method2_ordereddict(data):
    """Using OrderedDict.fromkeys()"""
    return list(OrderedDict.fromkeys(data))

def method3_loop(data):
    """Using a loop and a set"""
    result = []
    seen = set()
    for item in data:
        if item not in seen:
            seen.add(item)
            result.append(item)
    return result

def time_function(func, data, runs=100):
    """Measure execution time of a function"""
    start_time = time.time()
    for _ in range(runs):
        func(data)
    end_time = time.time()
    return (end_time - start_time) / runs

## Test data
small_list = list(range(100)) + list(range(50))  ## 150 items, 50 duplicates
medium_list = list(range(1000)) + list(range(500))  ## 1500 items, 500 duplicates
large_list = list(range(10000)) + list(range(5000))  ## 15000 items, 5000 duplicates

## Test results
print("Performance comparison (average time in seconds over 100 runs):\n")

print("Small list (150 items, 50 duplicates):")
print(f"dict.fromkeys():       {time_function(method1_dict, small_list):.8f}")
print(f"OrderedDict.fromkeys(): {time_function(method2_ordereddict, small_list):.8f}")
print(f"Loop and set:          {time_function(method3_loop, small_list):.8f}")

print("\nMedium list (1,500 items, 500 duplicates):")
print(f"dict.fromkeys():       {time_function(method1_dict, medium_list):.8f}")
print(f"OrderedDict.fromkeys(): {time_function(method2_ordereddict, medium_list):.8f}")
print(f"Loop and set:          {time_function(method3_loop, medium_list):.8f}")

print("\nLarge list (15,000 items, 5,000 duplicates):")
print(f"dict.fromkeys():       {time_function(method1_dict, large_list):.8f}")
print(f"OrderedDict.fromkeys(): {time_function(method2_ordereddict, large_list):.8f}")
print(f"Loop and set:          {time_function(method3_loop, large_list):.8f}")

Ejecute la prueba de rendimiento:

python3 performance_test.py

La salida mostrará el rendimiento de cada método con diferentes tamaños de lista:

Performance comparison (average time in seconds over 100 runs):

Small list (150 items, 50 duplicates):
dict.fromkeys():       0.00000334
OrderedDict.fromkeys(): 0.00000453
Loop and set:          0.00000721

Medium list (1,500 items, 500 duplicates):
dict.fromkeys():       0.00003142
OrderedDict.fromkeys(): 0.00004123
Loop and set:          0.00007621

Large list (15,000 items, 5,000 duplicates):
dict.fromkeys():       0.00035210
OrderedDict.fromkeys(): 0.00044567
Loop and set:          0.00081245

Los números reales pueden variar según su sistema, pero debería notar algunos patrones.

Mejores Prácticas

Basándonos en nuestros experimentos, establezcamos algunas mejores prácticas. Cree un archivo llamado best_practices.py:

"""
Best Practices for Converting a List to a Set While Preserving Order
"""

## Example 1: For Python 3.7+, use dict.fromkeys() for best performance
def preserve_order_modern(lst):
    """Best method for Python 3.7+ - using dict.fromkeys()"""
    return list(dict.fromkeys(lst))

## Example 2: For compatibility with older Python versions, use OrderedDict
from collections import OrderedDict

def preserve_order_compatible(lst):
    """Compatible method for all Python versions - using OrderedDict"""
    return list(OrderedDict.fromkeys(lst))

## Example 3: When you need to process elements while preserving order
def preserve_order_with_processing(lst):
    """Process elements while preserving order"""
    result = []
    seen = set()

    for item in lst:
        ## Option to process the item here
        processed_item = str(item).lower()  ## Example processing

        if processed_item not in seen:
            seen.add(processed_item)
            result.append(item)  ## Keep original item in the result

    return result

## Demo
data = ["Apple", "banana", "Orange", "apple", "Pear", "BANANA"]

print("Original list:", data)
print("Method 1 (Python 3.7+):", preserve_order_modern(data))
print("Method 2 (Compatible):", preserve_order_compatible(data))
print("Method 3 (With processing):", preserve_order_with_processing(data))

Ejecute el archivo:

python3 best_practices.py

La salida muestra cómo cada método maneja los datos:

Original list: ['Apple', 'banana', 'Orange', 'apple', 'Pear', 'BANANA']
Method 1 (Python 3.7+): ['Apple', 'banana', 'Orange', 'apple', 'Pear', 'BANANA']
Method 2 (Compatible): ['Apple', 'banana', 'Orange', 'apple', 'Pear', 'BANANA']
Method 3 (With processing): ['Apple', 'Orange', 'Pear']

Observe que el Método 3 considera "Apple" y "apple" como el mismo elemento debido al procesamiento a minúsculas.

Recomendaciones

Basándonos en nuestros experimentos, aquí hay algunas recomendaciones:

  1. Para Python 3.7 y posteriores, use dict.fromkeys() para obtener el mejor rendimiento.
  2. Para compatibilidad con todas las versiones de Python, use OrderedDict.fromkeys().
  3. Cuando necesite realizar un procesamiento personalizado mientras verifica duplicados, use el enfoque de bucle y conjunto (loop and set).
  4. Considere la sensibilidad a mayúsculas y minúsculas y otras transformaciones según sus requisitos específicos.

Resumen

En este tutorial, ha aprendido:

  1. Las diferencias fundamentales entre las listas y los conjuntos (sets) de Python

  2. Por qué convertir una lista en un conjunto normalmente causa la pérdida del orden

  3. Múltiples métodos para convertir una lista en un conjunto preservando el orden original:

    • Usando dict.fromkeys() en Python 3.7+
    • Usando OrderedDict.fromkeys() para compatibilidad con versiones anteriores de Python
    • Usando un bucle con un conjunto (set) para un procesamiento más complejo
  4. Cómo aplicar estas técnicas a problemas del mundo real como el análisis de texto

  5. Consideraciones de rendimiento y mejores prácticas para diferentes escenarios

Estas técnicas son valiosas para la limpieza de datos, la eliminación de duplicados de la entrada del usuario, el procesamiento de opciones de configuración y muchas otras tareas comunes de programación. Al elegir el enfoque correcto según sus requisitos específicos, puede escribir código Python más limpio y eficiente.