[Google Sheets] Transformer un tableau en liste exploitable plus facilement
Bonjour,
Comment concilier ergonomie et efficacité ?
Il est plus facile de rentrer des données sous forme de tableau. Prenons l'exemple d'une équipe dont on tient à jour un tableau de "présence" avec ces codes
CP=congés payés, EF=événement de famille, F=formation, Mat=maternité, P=présence, RTT
Lundi | Mardi | Mercredi | Jeudi | Vendredi | |
Matt | P | P | P | P | P |
Karim | CP | CP | CP | P | P |
Tim | F | F | F | ||
Gaëlle | Mat | Mat | Mat | Mat | Mat |
Joachim | EF | EF | P | P | P |
Marghe | P | P | P | RTT | RTT |
Julie | P | P | P | P | P |
On conçoit que mettre ces données sur un tableau structuré est plus facile que de rentrer une liste (et évite les redondances ou indomptabilités s'il advenait que quelqu'un mette 2 codes pour le même jour et la même personne). Pourtant, si on veut accéder à ces données, faire des analyses, des statistiques, des cumuls, il serait plus intéressant de travailler sur une pseudo-base de données (qui est plutôt disons-le une liste).
Nom | Jour | Présence |
Matt | Lundi | P |
Matt | Mardi | P |
Matt | Mercredi | P |
Matt | Jeudi | P |
Matt | Vendredi | P |
Karim | Lundi | CP |
Karim | Mardi | CP |
Karim | Mercredi | CP |
Karim | Jeudi | P |
Karim | Vendredi | P |
Tim | Mercredi | F |
Tim | Jeudi | F |
Tim | Vendredi | F |
Gaëlle | Lundi | Mat |
Gaëlle | Mardi | Mat |
Gaëlle | Mercredi | Mat |
Gaëlle | Jeudi | Mat |
Gaëlle | Vendredi | Mat |
Joachim | Lundi | EF |
Joachim | Mardi | EF |
Joachim | Mercredi | P |
Joachim | Jeudi | P |
Joachim | Vendredi | P |
Marghe | Lundi | P |
Marghe | Mardi | P |
Marghe | Mercredi | P |
Marghe | Jeudi | RTT |
Marghe | Vendredi | RTT |
Julie | Lundi | P |
Julie | Mardi | P |
Julie | Mercredi | P |
Julie | Jeudi | P |
Julie | Vendredi | P |
Les formules de Google Sheets permettent de passer de l'un à l'autre. Pour cela on utilisera les fonctions suivantes :
columns
flatten
mod
query
roundup
rows
sequence
transpose
vlookup
je donne la solution tout de suite, tab
étant le nom du tableau, sachant je donnerai des explications ci-dessous (excellent moyen de découvrir ou revisiter ces fonctions)
=query({
arrayformula(vlookup(arrayformula(ROUNDDOWN(flatten(sequence(rows(tab);columns(tab);0;1))/columns(tab))*columns(tab)+1);{flatten(sequence(rows(tab);columns(tab);1;1))\flatten(tab)};2;0))\
arrayformula(vlookup(mod(flatten(sequence(rows(tab);columns(tab);0;1));columns(tab))+1;{flatten(sequence(rows(tab);columns(tab);1;1))\flatten(tab)};2;0))\
flatten(tab)
};"select * where Col1 is not null and Col2 is not null and Col3 is not null";0)
https://docs.google.com/spreadsheets/d/1CgPHVY_PHgS_DoX1ifkXWOyTrmr7ggcxMyU5udcODE4/copy
Je précise que l'on trouve des solutions comme celle de BenCollins https://www.benlcollins.com/spreadsheets/unpivot-in-google-sheets/. La démarche est en effet similaire mais le résultat auquel on parvient ici est un peu plus simple et plus souple de mise en place.
FLATTEN
Cette fonction permet de mettre en colonne la plage de données, la prise en compte des cellules est la même que la lecture latine : de gauche à droite et de haut en bas en dessinant un Z
=flatten(tab)
On aura donc le résultat suivant de la plage citée plus haut
Lundi |
Mardi |
Mercredi |
Jeudi |
Vendredi |
Matt |
P |
P |
P |
P |
P |
Karim |
CP |
CP |
CP |
P |
P |
Tim |
F |
F |
F |
Gaëlle |
Mat |
Mat |
Mat |
Mat |
Mat |
Joachim |
EF |
EF |
P |
P |
P |
Marghe |
P |
P |
P |
RTT |
RTT |
Julie |
P |
P |
P |
P |
P |
on a tous les éléments de la 3ème colonne (Valeurs), y compris la première cellule vierge en haut à gauche, et un peu plus ... on verra plus tard comment les cellules Noms et Jours seront supprimées.
SEQUENCE
sequence est une fonction qui permet de remplir un tableau de valeurs
=SEQUENCE(lignes; colonnes; début; pas)
le nombre de lignes du tableau tab est =rows(tab)
soit 8 et le nombre de colonnes =columns(tab)
soit 6 ... pour alléger la lecture on utilisera le résultat 8 et 6
=sequence(8;6;1;1)
donne donc
1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 |
31 | 32 | 33 | 34 | 35 | 36 |
37 | 38 | 39 | 40 | 41 | 42 |
43 | 44 | 45 | 46 | 47 | 48 |
ce qui permet un repérage des valeurs transformées par FLATTEN. On peut ainsi construire un tableau de correspondance en juxtaposant via \
les 2 colonnes
={flatten(sequence(8;6;1;1))\flatten(tab)}
1 | |
2 | Lundi |
3 | Mardi |
4 | Mercredi |
5 | Jeudi |
6 | Vendredi |
7 | Matt |
8 | P |
9 | P |
10 | P |
11 | P |
12 | P |
13 | Karim |
14 | CP |
15 | CP |
16 | CP |
17 | P |
18 | P |
19 | Tim |
20 | |
21 | |
22 | F |
23 | F |
24 | F |
25 | Gaëlle |
26 | Mat |
27 | Mat |
28 | Mat |
29 | Mat |
30 | Mat |
31 | Joachim |
32 | EF |
33 | EF |
34 | P |
35 | P |
36 | P |
37 | Marghe |
38 | P |
39 | P |
40 | P |
41 | RTT |
42 | RTT |
43 | Julie |
44 | P |
45 | P |
46 | P |
47 | P |
48 | P |
Dernier élément fondamental (on passera ensuite au mixage des éléments de "base") : repérer les en-têtes de colonnes et "en-têtes" de ligne.
Les en-têtes de colonnes (ici les jours) sont les éléments
1 2 3 4 5 6
c'est donc le reste de la division par 6 des valeurs précédentes, soit avec la fonction modulo
=arrayformula(mod(sequence(8;6;0;1);6)+1)
1 | 2 | 3 | 4 | 5 | 6 |
1 | 2 | 3 | 4 | 5 | 6 |
1 | 2 | 3 | 4 | 5 | 6 |
1 | 2 | 3 | 4 | 5 | 6 |
1 | 2 | 3 | 4 | 5 | 6 |
1 | 2 | 3 | 4 | 5 | 6 |
1 | 2 | 3 | 4 | 5 | 6 |
1 | 2 | 3 | 4 | 5 | 6 |
Les "en-têtes" de ligne (ici les noms) sont les éléments
1 7 13 19 25 31 37 43
qui s'obtiendront par la valeur entière de la division des valeurs précédentes par 6, soit :
=arrayformula(ROUNDDOWN(sequence(8;6;0;1)/6)*6+1)
1 | 1 | 1 | 1 | 1 | 1 |
7 | 7 | 7 | 7 | 7 | 7 |
13 | 13 | 13 | 13 | 13 | 13 |
19 | 19 | 19 | 19 | 19 | 19 |
25 | 25 | 25 | 25 | 25 | 25 |
31 | 31 | 31 | 31 | 31 | 31 |
37 | 37 | 37 | 37 | 37 | 37 |
43 | 43 | 43 | 43 | 43 | 43 |
on a tous les éléments pour combiner via des RECHERCHEV/VLOOKUP ... à suivre
Dernière étape ... utiliser les ingrédients vus plus haut :
en A et B : la liste des repères et des données de toutes les colonnes et lignes
=flatten(tab)
en D : la liste mise en colonne par flatten des repères des en-têtes de colonnes ... d'où en E les en-têtes elle-même issues de A,B par VLOOKUP
=arrayformula(vlookup(
mod(flatten(sequence(8;6;0;1));6)+1;
{flatten(sequence(8;6;1;1))\flatten(tab)};
2;0))
en G : la liste mise en colonne par flatten des repères des "en-têtes" de lignes ... d'où en H les en-têtes elle-même issues de A,B par VLOOKUP
=arrayformula(vlookup(
arrayformula(ROUNDDOWN(flatten(sequence(8;6;0;1))/6)*6+1);
{flatten(sequence(8;6;1;1))\flatten(tab)};
2;0))
le résultat attendu est donc en H, E et B (dans cet ordre) sur lequel on applique query pour ne pas retenir les lignes où une case est vide, ce qui enlève automatiquement les en-têtes de la colonne H
on remplacera aussi les valeurs 8 et 6 par rows(tab) et columns(tab)
A | B | C | D | E | F | G | H |
Repère | Donnée | Jours | Noms | ||||
1 | 1 | 1 | |||||
2 | Lundi | 2 | Lundi | 1 | |||
3 | Mardi | 3 | Mardi | 1 | |||
4 | Mercredi | 4 | Mercredi | 1 | |||
5 | Jeudi | 5 | Jeudi | 1 | |||
6 | Vendredi | 6 | Vendredi | 1 | |||
7 | Matt | 1 | 7 | Matt | |||
8 | P | 2 | Lundi | 7 | Matt | ||
9 | P | 3 | Mardi | 7 | Matt | ||
10 | P | 4 | Mercredi | 7 | Matt | ||
11 | P | 5 | Jeudi | 7 | Matt | ||
12 | P | 6 | Vendredi | 7 | Matt | ||
13 | Karim | 1 | 13 | Karim | |||
14 | CP | 2 | Lundi | 13 | Karim | ||
15 | CP | 3 | Mardi | 13 | Karim | ||
16 | CP | 4 | Mercredi | 13 | Karim | ||
17 | P | 5 | Jeudi | 13 | Karim | ||
18 | P | 6 | Vendredi | 13 | Karim | ||
19 | Tim | 1 | 19 | Tim | |||
20 | 2 | Lundi | 19 | Tim | |||
21 | 3 | Mardi | 19 | Tim | |||
22 | F | 4 | Mercredi | 19 | Tim | ||
23 | F | 5 | Jeudi | 19 | Tim | ||
24 | F | 6 | Vendredi | 19 | Tim | ||
25 | Gaëlle | 1 | 25 | Gaëlle | |||
26 | Mat | 2 | Lundi | 25 | Gaëlle | ||
27 | Mat | 3 | Mardi | 25 | Gaëlle | ||
28 | Mat | 4 | Mercredi | 25 | Gaëlle | ||
29 | Mat | 5 | Jeudi | 25 | Gaëlle | ||
30 | Mat | 6 | Vendredi | 25 | Gaëlle | ||
31 | Joachim | 1 | 31 | Joachim | |||
32 | EF | 2 | Lundi | 31 | Joachim | ||
33 | EF | 3 | Mardi | 31 | Joachim | ||
34 | P | 4 | Mercredi | 31 | Joachim | ||
35 | P | 5 | Jeudi | 31 | Joachim | ||
36 | P | 6 | Vendredi | 31 | Joachim | ||
37 | Marghe | 1 | 37 | Marghe | |||
38 | P | 2 | Lundi | 37 | Marghe | ||
39 | P | 3 | Mardi | 37 | Marghe | ||
40 | P | 4 | Mercredi | 37 | Marghe | ||
41 | RTT | 5 | Jeudi | 37 | Marghe | ||
42 | RTT | 6 | Vendredi | 37 | Marghe | ||
43 | Julie | 1 | 43 | Julie | |||
44 | P | 2 | Lundi | 43 | Julie | ||
45 | P | 3 | Mardi | 43 | Julie | ||
46 | P | 4 | Mercredi | 43 | Julie | ||
47 | P | 5 | Jeudi | 43 | Julie | ||
48 | P | 6 | Vendredi | 43 | Julie |
à noter que H aurait pu être obtenu comme E en transposant les données
=arrayformula(vlookup((roundup(flatten(sequence(6;8;1;1)/columns(tab))));{flatten(sequence(6;8;1;1))\flatten(transpose(tab))};2;0))
C'est pas simple, je le conçois et je ne suis pas sûr d'avoir été suffisamment didactique ! Mais refaire l'opération de A à Z peut-être un bon entraînement !! Enjoy.