Suppression et extraction des éléments en double d’une liste (tableau) en Python

Affaires

Cette section décrit comment générer une nouvelle liste en Python en supprimant ou en extrayant les éléments en double d'une liste (tableau).

Les détails suivants sont décrits ici.

  • Supprimez les éléments en double et générez de nouvelles listes.
    • Ne pas conserver l'ordre de la liste originale:set()
    • Préserve l'ordre de la liste originale: dict.fromkeys(),sorted()
    • Tableau bidimensionnel (liste de listes)
  • Extraire les éléments en double et générer une nouvelle liste
    • Ne pas conserver l'ordre de la liste originale
    • Préserve l'ordre de la liste originale
    • Tableau bidimensionnel (liste de listes)

Le même concept peut être appliqué aux tuples au lieu des listes.

Voir l'article suivant pour

  • Si vous voulez déterminer si une liste ou un tuple comporte des éléments en double
  • Si vous voulez extraire les éléments qui sont communs ou non entre plusieurs listes au lieu d'une seule liste

Notez que les listes peuvent stocker différents types de données et sont strictement différentes des tableaux. Si vous souhaitez manipuler des tableaux dans le cadre de processus nécessitant des adresses mémoire et des tailles de mémoire ou le traitement numérique de données volumineuses, utilisez array (bibliothèque standard) ou NumPy.

Supprimez les éléments en double et générez de nouvelles listes.

Ne pas conserver l'ordre de la liste originale: set()

S'il n'y a pas besoin de préserver l'ordre de la liste originale, utilisez set(), qui génère un ensemble de type set.

Le type set est un type de données qui ne comporte pas d'éléments en double. Lorsqu'une liste ou un autre type de données est passé à set(), les valeurs dupliquées sont ignorées et un objet de type set est retourné dans lequel seules les valeurs uniques sont des éléments.

Si vous voulez en faire un tuple, utilisez tuple().

l = [3, 3, 2, 1, 5, 1, 4, 2, 3]

print(set(l))
# {1, 2, 3, 4, 5}

print(list(set(l)))
# [1, 2, 3, 4, 5]

Bien sûr, on peut aussi le laisser comme set. Voir l'article suivant pour plus d'informations sur le type set.

Préserve l'ordre de la liste originale: dict.fromkeys(),sorted()

Si vous voulez préserver l'ordre de la liste originale, utilisez la méthode de classe fromkeys() du type dictionnaire ou la fonction intégrée sorted().

dict.fromkeys() crée un nouvel objet dictionnaire dont les clés sont des listes, des tuples, etc. spécifiés dans les arguments. Si le deuxième argument est omis, la valeur est None.

Comme les clés de dictionnaire n'ont pas d'éléments dupliqués, les valeurs dupliquées sont ignorées comme dans set(). De plus, un objet dictionnaire peut être passé comme argument à list() pour obtenir une liste dont les éléments sont des clés de dictionnaire.

print(dict.fromkeys(l))
# {3: None, 2: None, 1: None, 5: None, 4: None}

print(list(dict.fromkeys(l)))
# [3, 2, 1, 5, 4]

Il est garanti depuis Python 3.7 (CPython est 3.6) que dict.fromkeys() préserve l'ordre de la séquence d'arguments. Les versions antérieures utilisent la fonction intégrée sorted() comme suit.

Spécifiez la méthode de tuple de liste index() pour l'argument key de sorted, qui renvoie une liste triée d'éléments.

index() est une méthode qui renvoie l'indice de la valeur (le numéro de l'élément dans la liste), qui peut être spécifié comme clé de sorted() pour trier la liste en fonction de l'ordre de la liste d'origine. L'argument key est spécifié comme un objet appelable (callable), il ne faut donc pas écrire ().

print(sorted(set(l), key=l.index))
# [3, 2, 1, 5, 4]

Tableau bidimensionnel (liste de listes)

Pour les tableaux à deux dimensions (listes de listes), la méthode utilisant set() ou dict.fromkeys() donne lieu à une TypeError.

l_2d = [[1, 1], [0, 1], [0, 1], [0, 0], [1, 0], [1, 1], [1, 1]]

# l_2d_unique = list(set(l_2d))
# TypeError: unhashable type: 'list'

# l_2d_unique_order = dict.fromkeys(l_2d)
# TypeError: unhashable type: 'list'

En effet, les objets non hachables tels que les listes ne peuvent pas être des éléments de type set ou des clés de type dict.

Définissez les fonctions suivantes L'ordre de la liste originale est préservé et fonctionne pour les listes unidimensionnelles et les tuples.

def get_unique_list(seq):
    seen = []
    return [x for x in seq if x not in seen and not seen.append(x)]

print(get_unique_list(l_2d))
# [[1, 1], [0, 1], [0, 0], [1, 0]]

print(get_unique_list(l))
# [3, 2, 1, 5, 4]

La notation de compréhension de liste est utilisée.

Ici, nous utilisons les éléments suivants

  • Si X dans “X et Y” est faux dans l'évaluation en court-circuit de l'opérateur and, alors Y n'est pas évalué (pas exécuté).
  • La méthode append() renvoie None.

Si les éléments de la liste originale seq n'existent pas dans la vue, then et after sont évalués.
seen.append(x) est exécuté et l'élément est ajouté à seen.
Parce que la méthode append() renvoie None et None est False, non vu.append(x) évalue à True.
L'expression conditionnelle dans la notation de compréhension de liste devient vraie et est ajoutée comme élément de la liste finale générée.

Si les éléments de la liste originale seq sont présents dans seen, alors x non présent dans seen est Faux, et l'expression conditionnelle de l'expression de compréhension de la liste est Faux.
Par conséquent, ils ne sont pas ajoutés comme éléments de la liste finale générée.

Une autre méthode consiste à définir l'axe de l'argument dans la fonction np.unique() de NumPy, bien que le résultat soit trié.

Extraire les éléments en double et générer une nouvelle liste

Ne pas conserver l'ordre de la liste originale

Pour extraire uniquement les éléments en double de la liste originale, utilisez collections.Counter().
Renvoie un collections.Counter (une sous-classe de dictionnaire) avec les éléments comme clés et le nombre d'éléments comme valeurs.

import collections

l = [3, 3, 2, 1, 5, 1, 4, 2, 3]

print(collections.Counter(l))
# Counter({3: 3, 2: 2, 1: 2, 5: 1, 4: 1})

Comme il s'agit d'une sous-classe de dictionnaire, items() peut être utilisé pour extraire les clés et les valeurs. Il suffit d'extraire les clés dont le nombre est égal ou supérieur à deux.

print([k for k, v in collections.Counter(l).items() if v > 1])
# [3, 2, 1]

Préserve l'ordre de la liste originale

Comme le montre l'exemple ci-dessus, depuis Python 3.7, les clés de collections.Counter conservent l'ordre de la liste originale et ainsi de suite.

Dans les versions antérieures, le tri avec sorted() est suffisant, tout comme la suppression des éléments en double.

print(sorted([k for k, v in collections.Counter(l).items() if v > 1], key=l.index))
# [3, 2, 1]

Si vous souhaitez extraire les doublons tels quels, il suffit de laisser dans la liste d'origine les éléments dont le numéro est égal ou supérieur à deux. L'ordre est également préservé.

cc = collections.Counter(l)
print([x for x in l if cc[x] > 1])
# [3, 3, 2, 1, 1, 2, 3]

Tableau bidimensionnel (liste de listes)

Pour les tableaux à deux dimensions (listes de listes), les fonctions suivantes sont possibles lorsque l'ordre de la liste d'origine n'est pas conservé et lorsqu'il est conservé, respectivement. Cela fonctionne également pour les listes unidimensionnelles et les tuples.

l_2d = [[1, 1], [0, 1], [0, 1], [0, 0], [1, 0], [1, 1], [1, 1]]
def get_duplicate_list(seq):
    seen = []
    return [x for x in seq if not seen.append(x) and seen.count(x) == 2]

def get_duplicate_list_order(seq):
    seen = []
    return [x for x in seq if seq.count(x) > 1 and not seen.append(x) and seen.count(x) == 1]

print(get_duplicate_list(l_2d))
# [[0, 1], [1, 1]]

print(get_duplicate_list_order(l_2d))
# [[1, 1], [0, 1]]

print(get_duplicate_list(l))
# [3, 1, 2]

print(get_duplicate_list_order(l))
# [3, 2, 1]

Si vous voulez extraire avec des doublons, laissez les éléments de la liste originale avec un compte de deux ou plus.

print([x for x in l_2d if l_2d.count(x) > 1])
# [[1, 1], [0, 1], [0, 1], [1, 1], [1, 1]]

Notez que puisque la complexité de calcul de count() est O(n), la fonction présentée ci-dessus qui exécute count() de manière répétée est très inefficace. Il existe peut-être une méthode plus intelligente.

Counter est une sous-classe de dictionnaire, donc si vous passez une liste ou un tuple dont les éléments sont des listes ou d'autres objets non hachables à collections.Counter(), une erreur se produira et vous ne pourrez pas l'utiliser.

# print(collections.Counter(l_2d))
# TypeError: unhashable type: 'list'