2014-06-19 6 views
0

J'ai des difficultés avec les listes imbriquées de listes en Python (ce qui est la structure de GeoJSON coordonne)explosion récursive une liste de la liste « Liste atomique »

Voici un exemple

exemple mis à jour éviter toute confusion

DictofCoordinates = { 
'a': [1,1], 
'b': [[2, 2], [2,2], [2, 2]], 
'c': [[[3,3], [3, 3], [3, 3]]], 
'd': [[[41, 41], [41, 41]], 
    [[42, 42], [42, 42]]] 
} 

ce que je veux obtenir est la liste qui ne contient anyhing autre que les paires (de coordonnées). c'est ce que j'appelle "liste atomique de la liste" (faute d'un meilleur terme)

si

- for a : the list [1, 1] 
- for b : [[2, 2], [2,2], [2, 2]] 
- for c : [[3,3], [3, 3], [3, 3]] 
- for d : the two lists [[41, 41], [41, 41]] and [[42, 42], [42, 42]]] 

prenant inspriation de here qui est ce que j'ai essayé

def ExplodeTolist(xList): 
for x1 in xList: 
    if isinstance(x1[0], (float, int, long)): 
     yield x1 
    else: 
     for x2 in ExplodeTolist(x1): 
      yield x2 

mais cela ne fonctionne pas

for x in ExplodeTolist(DictofCoordinates.values()): 
    print x   

toute aide appréciée. Merci

+0

Ce que la sortie que vous voulez obtenir? – tmr232

+0

Que diable est une * "liste atomique de liste" *? – jonrsharpe

+0

Je pense qu'il veut juste l'aplatir .... mais la question est de savoir ce que __ * ne fonctionne pas * __ signifie réellement? –

Répondre

1

En fait, vous avez seulement besoin de vérifier si l'élément [0] est une liste.

def flatten(items): 
    for elem in items: 
     if isinstance(elem[0],list): 
      for sub_elem in elem: 
       yield sub_elem 
     else: 
      yield elem 

print list(flatten(DictofCoordinates.values())) 
[[1, 1], [[3, 3], [3, 3], [3, 3]], [2, 2], [2, 2], [2, 2], [[41, 41], [41, 41]], [[42, 42], [42, 42]]] 

Pour votre nouvelle sortie correspondent:

def flatten(items): 
    for elem in items: 
     if sum(isinstance(i, list) for i in elem) == 0 or sum(isinstance(i, list) for i in elem[0]) == 0: 
      yield elem 
     else: 
      for sub_elem in elem: 
       yield sub_elem 

print (list(flatten(DictofCoordinates.values()))) 
[[1, 1], [[3, 3], [3, 3], [3, 3]], [[2, 2], [2, 2], [2, 2]], [[41, 41], [41, 41]], [[42, 42], [42, 42]]] 
+0

Pourquoi utilisez-vous 'sum' au lieu de' any' ou 'all'? – jpmc26

0

Cette fonction retournera les atomes que vous décrivez.

def getAtoms(lst): 
    for l in lst: 
     yield l 
+0

Non ce ne sera pas. C'est juste tous les éléments de la liste la plus externe – colinro

+0

Chaque valeur dans le dictionnaire est une liste. Si vous passez cette fonction à l'une de ces listes, par ex. la valeur d: [[[41, 41], [41, 41]], [[42, 42], [42, 42]]], cela donnera [[41, 41], [41, 41]] puis [[42, 42], [42, 42]] dans deux appels successifs gen.next(). C'est ce que montre l'exemple OP. – ScottO

+0

Je vois ce que vous voulez dire maintenant. J'avais interprété différemment la question – colinro

2

Si je comprends bien, vous voulez juste pour traiter le contenu de chaque liste, si elle contient plusieurs listes. Sinon, vous voulez retourner la liste elle-même. Je pense que la grosse erreur que vous faites est que votre fonction est récursive, donc elle va aussi loin que possible, et vous finissez avec juste un itérateur sur tous les points. Essayez ceci à la place:

# You might want to modify this method to 
# return False if it passes isinstance(x, basestring) 
def is_iterable(x): 
    try: 
     iter(x) 
     return True 
    except TypeError: 
     return False 

def get_elements(coordinate_dict): 
    for v in coordinate_dict.values(): 
     if is_iterable(v[0]): 
      for i in v: 
       yield i 
     else: 
      yield v 

Lorsqu'il détecte un contenu itérable, il parcourt la liste et renvoie les éléments. Si le contenu de la liste est pas itérable, il retourne simplement la liste. La différence clé est que quand il trouve des contenus itératifs, il itère seulement une couche profonde. Comme vu dans les commentaires, il ya un débat sur la façon de tester si quelque chose est itérable. Je recommande de voir In Python, how do I determine if an object is iterable? et ses réponses pour plus de discussion sur ce sujet.

Voici la sortie. Il est un peu irrecevable parce dict est non ordonnée, mais tous les éléments sont là:

>>> for i in get_elements(d): 
...  print i 
... 
[1, 1] 
[[3, 3], [3, 3], [3, 3]] 
[2, 2] 
[2, 2] 
[2, 2] 
[[41, 41], [41, 41]] 
[[42, 42], [42, 42]] 
+0

'à partir des collections import Iterable' –

+0

une implémentation plus rapide de is_iterable retournerait' True si getattr (x, '__iter__', False) sinon False'. Il est 2-3 fois plus lent de compter sur la gestion des exceptions – colinro

+0

@colinro J'ai basé mon test itérable désactiver [cette réponse] (http://stackoverflow.com/a/1952481/1394393). À mon avis, c'est simplement la façon la plus fiable de dire si quelque chose est itérable. N'importe quel nombre de techniques pourrait être employé. Je ne connais pas de consensus clair sur la façon Pythonienne de faire ce test. – jpmc26