Résumé en français : On vous donne une chaine de caractères composée de “chiffres” (‘0’ à ‘9’). Vous devez écrire une fonction qui renvoie une chaine où chaque chiffre est répété le nombre de fois correspondant à sa valeur. Par exemple avec la chaine “312”, on doit répéter 3 fois le “3”, 1 fois le “1” et 2 fois le “2”, ce qui donne la chaine “333122”.
Version classique
Première idée, utiliser 2 boucles. La première pour récupérer un à un les caractères de la chaine et la seconde pour dupliquer le bon nombre de fois chacun de ces caractères.
python
def explose(s):
sortie = '' # initialisation du résultat final
for c in s: # on parcourt la chaine
for n in range(int(c)): # on ajoute le bon nombre de fois...
sortie += c # ...le caractère
return sortie # retour du résultat
>> explose("312")
'333122'
>> explose("302")
'33322'
>> explose("102269")
'12222666666999999999'
Une seule boucle + répéter
En Python, JavaScript ou APL, il est simple de répéter un caractère :
Python
>> 'a' * 5
'aaaaa'
JavaScript
>> 'a'.repeat(5)
'aaaaa'
APL
5 ⍴ 'a'
aaaaa
On peut également répéter un caractère 0 fois, dans ce cas on obtient la chaine vide. D’où cette seconde version :
Python
def explose(s):
sortie = ''
for c in s:
sortie += c * int(c) # on répète le caractère
return sortie
JavaScript
const explose = s => {
sortie = '';
for (c of s) sortie += c.repeat(+c); // Voir dessous pour +c
return sortie
}
>> + '5' // Transformer une chaine en nombre
5
>> Number('5') // Même chose que Number
5
Autres écritures : join, map, reduce
Nous devons transformer (map) chaque caractère en sa répétition, ce qui donne un tableau de taille celle de la chaine initiale :
Python
>> [c * int(c) for c in "312"] # Transformer 3 "chiffres"
['333', '1', '22'] # Tableau à 3 éléments
JavaScript
>> [..."312"].map(c => c.repeat(+c)) // map = transformation
['333', '1', '22']
APL
3 1 2 ⍴¨ '312' ⍝ le ¨ signifie "pour chaque"
┌───┬─┬──┐
│333│1│22│
└───┴─┴──┘
Il suffit ensuite de joindre les différents éléments, d’où cette troisième version :
Python
def explose(s):
return ''.join(c * int(c) for c in s)
>> explose("44012")
'44444444122'
JavaScript v1
const explose = s => [...s].map(c => c.repeat(+c)).join('')
>> explose('55011')
'555555555511'
JavaScript est tolérant sur les mélanges de types :
>> 'a'.repeat('3') // utilisation de '3' au lieu de 3
'aaa'
>> 3 * '4' // multiplication d'un nombre par un caractère
12
JavaScript v2
>> const explose = s => [...s].map(c => c.repeat(c)).join``
On peut également utiliser reduce, c’est-à-dire partir d’une chaine vide et au fur et à mesure ajouter les caractères répétés, voici une version en JavaScript :
const explose = s => [...s].reduce((a, c) => a + c.repeat(c), '')
>> explose("44012")
'44444444122'
APL
Nous avons déjà vu comment transformer une chaine en vecteur :
s ← '312'
⍎¨s ⍝ On obtient un vecteur de 3 caractères
3 1 2
Remarquons que nous devons dupliquer les caractères et ensuite les concaténer :
(3 ⍴ '3') (1 ⍴ '1') (2 ⍴ '2') ⍝ On duplique les caractères
┌───┬─┬──┐
│333│1│22│
└───┴─┴──┘
,/ (3 ⍴ '3') (1 ⍴ '1') (2 ⍴ '2') ⍝ Concaténation
┌──────┐
│333122│
└──────┘
C’est exactement ce que fait un produit interne f.g, à savoir :
x1 x2 x3 f.g y1 y2 y3 signifie réduction f/ appliquée à (x1 g y1) (x2 g y2) (x3 g y3)
3 1 2 ,.⍴ '312' ⍝ On duplique puis concatène
┌──────┐
│333122│
└──────┘
{(⍎¨⍵) ,.⍴ ⍵} '312' ⍝ Créons notre fonction
┌──────┐
│333122│
└──────┘
(⍎¨,.⍴⊢) '31402' ⍝ Même version sans utiliser ⍵
┌──────────┐
│3331444422│
└──────────┘
⍝ Version finale en APL
explose ← ⍎¨ ,.⍴ ⊢
explose '314159'
┌───────────────────────┐
│33314444155555999999999│
└───────────────────────┘
explose ← ∊ ⍎¨ ,.⍴ ⊢
explose '314159'
33314444155555999999999
Expressions régulières
Une autre idée est de ce dire que chaque “chiffre” doit être remplacé par sa duplication. Voyons comment on effectue des remplacements en Python et JavaScript :
javascript
>> 'bonjour'.replace('o','*') // Un seul 'o' sera remplacé par '*'
'b*njour'
>> 'bonjour'.replace(/o/g,'*') // Tous les 'o' sont remplacés
'b*nj*ur' // 'g' pour global
>> "3a1b22".replace(/\d/g, '*') // Remplacer les chiffres (digits)
'*a*b**'
>> '4032'.replace(/./g, v => 9 - v) // '.' = caractère quelconque
'5967' // Les chiffres sont remplacés par 9 - valeur
// Mettre toutes les voyelles en majuscules
>> "okjaicompris".replace(/a|e|i|o|u/g, c => c.toUpperCase())
'OkjAIcOmprIs'
D’où cette version finale en JavaScript :
const explose = s => s.replace(/./g, v => v.repeat(v))
python
Python a la méthode replace pour des remplacements simples.
>> 'bonjour'.replace('o','*') # Tous les 'o' sont remplacés
'b*nj*ur'
D’où l’idée de remplacer chacun des caractères de ‘0’ à ‘9’ par leur duplication :
def explose(s):
for i in range(10):
s = s.replace(str(i), str(i) * i)
return s
>> explose('314159')
'33314444155555999999999'
Pour utiliser des expressions régulières (Regex), nous devons importer la bibliothèque re.
>> import re
>> re.sub(r'\d','*','3a1b22') # Remplacer les chiffres par '*'
'*a*b**'
On peut également effectuer des transformations, pour cela on :
– recherche les éléments à modifier à l’aide d’une expression régulière
– récupère la chaine correspondante (group ou [0])
– effectue la transformation (lambda x : …)
# Mettre toutes les voyelles en majuscules
>> re.sub(r'a|e|i|o|u', lambda x: x.group().upper(), 'okjaicompris')
'OkjAIcOmprIs'
# Ecriture équivalente en utilisant [0]
>> re.sub(r'a|e|i|o|u', lambda x: x[0].upper(), 'okjaicompris')
'OkjAIcOmprIs'
# Transformer chaque chiffre en 9 - chiffre :
>> re.sub(r'.',lambda x: str(9 - int(x[0])), '4032')
'5967'
Ce qui nous donne cette version finale en Python :
import re
def explose(s):
return re.sub(r'.',lambda v: v[0] * int(v[0]), s)