[Résolu] Noms et profondeurs d'une liste imbriquée

Postez ici vos questions, réponses, commentaires ou suggestions - Les sujets seront ultérieurement répartis dans les archives par les modérateurs

Modérateur : Groupe des modérateurs

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

[Résolu] Noms et profondeurs d'une liste imbriquée

Messagepar Pierre-Yves Berrard » 06 Aoû 2018, 07:18

Bonjour,

Je cherche à récupérer les noms et niveaux de profondeur d'une liste imbriquée :

Code : Tout sélectionner

x <-
  list(
    A = list(A1 = list(A1w = NULL)),
    B = list(B1 = list(B1x = NULL), B2 = list(B2y = NULL, B2z_ = NULL))
  )

Code : Tout sélectionner

str(x)
# List of 2
#  $ A:List of 1
#   ..$ A1:List of 1
#   .. ..$ A1w: NULL
#  $ B:List of 2
#   ..$ B1:List of 1
#   .. ..$ B1x: NULL
#   ..$ B2:List of 2
#   .. ..$ B2y: NULL
#   .. ..$ B2z_: NULL

Le résultat attendu serait :

Code : Tout sélectionner

c(A = 0, A1 = 1, A1w = 2, B = 0, B1 = 1, B1x = 2, B2 = 1, B2y = 2, B2z_ = 2)

# A  A1 A1w   B  B1 B1x  B2 B2y B2z_
# 0   1   2   0   1   2   1   2    2

À noter que les noms des sous-niveaux ressemblent au niveaux supérieurs pour l'exemple, mais en réalité peuvent n'avoir rien en commun.

Je pensais m'en sortir facilement avec une fonction récursive, mais apparemment ce n'est pas si simple (ou bien je ne suis pas réveillé ce lundi matin...).
PY

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: Noms et profondeurs d'une liste imbriquée

Messagepar Pierre-Yves Berrard » 06 Aoû 2018, 15:28

J'ai trouvé une solution en passant par deux fonctions récursives (avec quasiment le même algorithme), la première pour les noms, la seconde pour les profondeurs :

Code : Tout sélectionner

hrc_names <- function(x) {

  if (is.null(x[[1]])) {
    names(x)
  } else {
    purrr::map2(
      names(x),
      lapply(x, hrc_names),
      c
    )
  }

}

Code : Tout sélectionner

hrc_prof <- function(x, prof = 0) {

  if (is.null(x[[1]])) {
    rep(prof, length(x))
  } else {
    purrr::map2(
      rep(prof, length(x)),
      lapply(x, hrc_prof, prof = prof + 1),
      c
    )
  }
 
}

Code : Tout sélectionner

setNames(
  unlist(hrc_prof(x)),
  unlist(hrc_names(x))
)

#  A   A1  A1w    B   B1  B1x   B2  B2y B2z_
#  0    1    2    0    1    2    1    2    2


Merci à tous ! (qui êtes apparemment en vacances)
PY

François Bonnot
Messages : 537
Enregistré le : 10 Nov 2004, 15:19
Contact :

Re: [Résolu] Noms et profondeurs d'une liste imbriquée

Messagepar François Bonnot » 27 Aoû 2018, 13:00

Bonjour,
Les vacances étant terminées, voici une solution avec une seule fonction récursive :

Code : Tout sélectionner

proflist <- function(z,level=0,result=NULL) {
    if (length(z)>0 && class(z)=="list")
        for (i in length(z):1) {
            names(level) <- names(z)[i]
            result <- c(level,proflist(z[[i]],level+1,result))
        }
    result
}

proflist(x)


EDIT : J'ai modifié la condition if afin que la fonction accepte des listes dont les membres n'ont pas la valeur NULL
François

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: [Résolu] Noms et profondeurs d'une liste imbriquée

Messagepar Pierre-Yves Berrard » 28 Aoû 2018, 08:38

Merci beaucoup François, ta solution simplifie considérablement mon code.
Ça valait le coup d'attendre !
PY


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Google [Bot] et 1 invité