3
votes

Comment annuler l'imbrication (annuler le niveau) d'une liste imbriquée inutile sans changer sa forme? (Python)

C'est assez différent de ce que j'ai trouvé dans de nombreux threads - je ne veux pas rendre la liste plate mais les niveaux non imbriqués comme suit:

[[[3, 3]]] devrait être [3, 3]

[[[3, 4], [3, 3]]] doit être [[3, 4], [3, 3]] mais pas [3, 4], [3, 3] ni [3, 4, 3, 3] car cela change complètement la structure.

Fondamentalement, je voulais réduire les niveaux pour obtenir le même len (a_list) dans la première et la deuxième itération avant la rupture de boucle. Mais mon idée est quelque peu fausse:

Ce code fonctionne pour tout sauf [[3], [4]] . Je ne sais pas ce qui ne va pas aujourd'hui parce que cela a fonctionné hier. Besoin d'aide pour corriger cette fonction. Maintenant, il renvoie [3] mais devrait rester inchangé.

# Unlevel list - reduce unnecessary nesting without changing nested lists structure
def unlevelList(l):
    if len(l) > 0 and isinstance(l, list):
        done = True
        while done == True:
            if isinstance(l[0], list):
                if len(l) == len(l[0]):
                    l = l[0]
                else:
                    l = l[0]
                    done = False
            else:
                done = False
        return l
    else:
        return l


1 commentaires

Je pense que votre implémentation rencontrera des problèmes si vos sous-listes sont de tailles différentes, c'est-à-dire si votre structure de données n'est pas rectangulaire.


3 Réponses :


7
votes

Je serais enclin à le faire avec la récursivité: si l'objet est une liste de longueur 1, enlevez le calque extérieur; puis, annulez récursivement le niveau de tous ses enfants.

When [[[3, 3]]] is unleveled, it becomes [3, 3]
When [[[3, 4], [3, 3]]] is unleveled, it becomes [[3, 4], [3, 3]]
When [[3], [4]] is unleveled, it becomes [[3], [4]]
When [[[3]]] is unleveled, it becomes 3
When [[[3], [3, 3]]] is unleveled, it becomes [[3], [3, 3]]

Résultat:

def unlevel(obj):
    while isinstance(obj, list) and len(obj) == 1:
        obj = obj[0]
    return obj

test_cases = [
    [[[3, 3]]],
    [[[3, 4], [3, 3]]],
    [[3], [4]],
    [[[3]]],
    [[[3], [3, 3]]]
]

for x in test_cases:
    print("When {} is unleveled, it becomes {}".format(x, unlevel(x)))

Edit: relisant votre question, je pense peut-être vous voulez que [[3], [4]] reste [[3], [4]] . Si tel est le cas, alors j'interprète les exigences comme étant "seulement enlever les crochets excédentaires de la couche supérieure; laisser les listes intérieures à un élément inchangées". Dans ce cas, vous n'avez pas besoin de récursivité. Supprimez simplement la liste du haut jusqu'à ce que vous n'en puissiez plus, puis renvoyez-la.

When [[[3, 3]]] is unleveled, it becomes [3, 3]
When [[[3, 4], [3, 3]]] is unleveled, it becomes [[3, 4], [3, 3]]
When [[3], [4]] is unleveled, it becomes [3, 4]
When [[[3]]] is unleveled, it becomes 3
When [[[3], [3, 3]]] is unleveled, it becomes [3, [3, 3]]

Résultat:

def unlevel(obj):
    while isinstance(obj, list) and len(obj) == 1:
        obj = obj[0]
    if isinstance(obj, list):
        return [unlevel(item) for item in obj]
    else:
        return obj

test_cases = [
    [[[3, 3]]],
    [[[3, 4], [3, 3]]],
    [[3], [4]],
    [[[3]]],
    [[[3], [3, 3]]]
]

for x in test_cases:
    print("When {} is unleveled, it becomes {}".format(x, unlevel(x)))

p >


5 commentaires

Cela redéfinit incorrectement [[[3], [3, 3]]] en [3, [3, 3]] , où je crois [[3 ], [3, 3]] est attendu.


@blhsing Je pense que vous avez raison. J'ai ajouté une approche supplémentaire.


Honnêtement pas mal. Ce "supports excédentaires uniquement" était ce que je recherchais. Merci pour 2 versions.


Ceci est fait mais je ne peux pas changer [[[[4]]]] pour obtenir une liste toujours. Donc, à la place, 4 veut avoir [4] .


Hmm, vous pourriez peut-être changer la dernière ligne en return obj if isinstance (obj, list) else [obj] . La réponse de Nathan garantit également que le résultat est une liste.



2
votes

Je recommande également une solution récursive

[[3], [3, 3]]
[3, 3]
[[3, 4], [3, 3]]
[[3], [4]]
[3]

Certains cas de test

test_cases = [
    [[[3], [3, 3]]],
    [[[3, 3]]],
    [[[3, 4], [3, 3]]],
    [[3], [4]],
    [[[3]]]
]

for i in test_cases:
    print(unnest(i))

donne

def unnest(l):
    if isinstance(l, list) and len(l) == 1 and isinstance(l[0], list):
        return unnest(l[0])
    return l


0 commentaires

1
votes

Ce code semble faire exactement ce que vous voulez. Conservez les listes sous forme de listes (mais plates).

import itertools

a = [[[[1, 2]]], [[2, 3, 4, 5]], [[[[[[134, 56]]]]]], 9, 8, 0]
res = []

for element in a:
  if isinstance(element, list):
    while len(element) == 1:
      element = list(itertools.chain(*element))
    res.append(element)
  else:
    res.append(element)

print(res)

Avec le résultat res étant [[1, 2], [2, 3, 4, 5], [134, 56], 9, 8, 0]


1 commentaires

Pas exactement ce que je cherchais (ne pas enlever les nids internes) mais c'est utile aussi.