3 votes

Comment enchaîner, puis "désenchaîner" une liste imbriquée ?

J'ai une liste imbriquée que je dois enchaîner, puis exécuter des métriques, puis "désenchaîner" dans son format imbriqué d'origine. Voici un exemple de données pour illustrer mon propos :

from itertools import chain

nested_list = [['x', 'xx', 'xxx'], ['yy', 'yyy', 'y', 'yyyy'], ['zz', 'z']]
chained_list = list(chain(*nested_list))
print("chained_list: \n", chained_list)
metrics_list = [str(chained_list[x]) +'_score' \
    for x in range(len(chained_list))]
print("metrics_list: \n", metrics_list) 
zipped_scores = list(zip(chained_list, metrics_list))
print("zipped_scores: \n", zipped_scores)

unchain_function = '????'

chained_list: 
 ['x', 'xx', 'xxx', 'yy', 'yyy', 'y', 'yyyy', 'zz', 'z']
metrics_list: 
 ['x_score', 'xx_score', 'xxx_score', 'yy_score', 'yyy_score', 'y_score', 'yyyy_score', 'zz_score', 'z_score']
zipped_scores: 
 [('x', 'x_score'), ('xx', 'xx_score'), ('xxx', 'xxx_score'), ('yy', 'yy_score'), ('yyy', 'yyy_score'), ('y', 'y_score'), ('yyyy', 'yyyy_score'), ('zz', 'zz_score'), ('z', 'z_score')]

Existe-t-il une fonction python ou un moyen pythonique d'écrire une "unchain_function" pour obtenir ce résultat souhaité ?

[
    [
        ('x', 'x_score'), 
        ('xx', 'xx_score'), 
        ('xxx', 'xxx_score')
    ],
    [
        ('yy', 'yy_score'), 
        ('yyy', 'yyy_score'), 
        ('y', 'y_score'),
        ('yyyy', 'yyyy_score')
    ],
    [
        ('zz', 'zz_score'), 
        ('z', 'z_score')
    ]
]

(background : ceci est pour exécuter des métriques sur des listes ayant une longueur supérieure à 100 000)

1voto

Green Cloak Guy Points 1650

Je ne sais pas à quel point c'est pythique, mais ça devrait marcher. Pour faire court, nous utilisons un Wrapper pour transformer une primitive immuable (qu'il est impossible de modifier sans la remplacer) en une variable mutable (on peut donc avoir plusieurs références à la même variable, chacune organisée différemment).

Nous créons une liste imbriquée identique sauf que chaque valeur est un Wrapper de la valeur correspondante de la liste originale. Ensuite, nous appliquons la même transformation pour dé-chaîner la liste wrapper. Nous copions les modifications de la liste chaînée traitée sur la liste wrapper chaînée, puis nous accédons à ces modifications à partir de la liste wrapper imbriquée et nous les déballons.

Je pense que l'utilisation d'une classe explicite et simple appelée Wrapper est plus facile à comprendre, mais vous pourriez faire essentiellement la même chose en utilisant une liste singleton pour contenir la variable au lieu d'une instance de Wrapper .

from itertools import chain

nested_list = [['x', 'xx', 'xxx'], ['yy', 'yyy', 'y', 'yyyy'], ['zz', 'z']]
chained_list = list(chain(*nested_list))

metrics_list = [str(chained_list[x]) +'_score' for x in range(len(chained_list))]
zipped_scores = list(zip(chained_list, metrics_list))

# create a simple Wrapper class, so we can essentially have a mutable primitive.
# We can put the Wrapper into two different lists, and modify its value without
# overwriting it.
class Wrapper:
    def __init__(self, value):
        self.value = value

# create a 'duplicate list' of the nested and chained lists, respectively, 
# such that each element of these lists is a Wrapper of the corresponding
# element in the above lists
nested_wrappers = [[Wrapper(elem) for elem in sublist] for sublist in nested_list]
chained_wrappers = list(chain(*nested_wrappers))

# now we have two references to the same MUTABLE Wrapper for each element of 
# the original lists - one nested, and one chained. If we change a property
# of the chained Wrapper, the change will reflect on the corresponding nested
# Wrapper. Copy the changes from the zipped scores onto the chained wrappers
for score, wrapper in zip(zipped_scores, chained_wrappers):
    wrapper.value = score

# then extract the values in the unchained list of the same wrappers, thus
# preserving both the changes and the original nested organization
unchained_list = [[wrapper.value for wrapper in sublist] for sublist in nested_wrappers]

Cela se termine par unchained_list égal à ce qui suit :

[[('x', 'x_score'), ('xx', 'xx_score'), ('xxx', 'xxx_score')], [('yy', 'yy_score'), ('yyy', 'yyy_score'), ('y', 'y_score'), ('yyyy', 'yyyy_score')], [('zz', 'zz_score'), ('z', 'z_score')]]

0voto

pylang Points 12013

Je pense que vous voulez simplement regrouper vos données en fonction d'une condition, c'est-à-dire la première lettre du premier index de chaque tuple.

Étant donné que

Vos données aplaties, zippées :

data = [
    ('x', 'x_score'), ('xx', 'xx_score'), ('xxx', 'xxx_score'),
    ('yy', 'yy_score'), ('yyy', 'yyy_score'), ('y', 'y_score'), ('yyyy', 'yyyy_score'),
    ('zz', 'zz_score'), ('z', 'z_score')
]

Code

[list(g) for _, g in itertools.groupby(data, key=lambda x: x[0][0])]

Sortie

[[('x', 'x_score'), ('xx', 'xx_score'), ('xxx', 'xxx_score')],
 [('yy', 'yy_score'),
  ('yyy', 'yyy_score'),
  ('y', 'y_score'),
  ('yyyy', 'yyyy_score')],
 [('zz', 'zz_score'), ('z', 'z_score')]]

Voir aussi

  • Ce site poste sur le fonctionnement de cet outil

0voto

venkatesh Points 92

Vous avez rendu l'algorithme très complexe, vous pouvez le faire en suivant les étapes simples indiquées ci-dessous :

  • Créez d'abord une liste vide imbriquée de la taille souhaitée.

    liste_formatée = [[] pour _ dans l'intervalle(3)]

  • Il suffit de boucler sur la liste et de la formater en conséquence

    pour K dans l'intervalle(0,3) :

          for i in nested_list[K]:
    
              formatted_list[K].append(i + '_score')
    
          print([formatted_list])

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X