
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)