Un peu de Scala vite fait pour faire chauffer le CPU :
Soit un numéro IBAN simple, présenté sous la forme d’une grosse chaîne de caractère :
FR7630057410821012122045021
Comment l’afficher à l’écran en le formatant de cette façon ?
FR76 3005 7410 8210 1212 2045 021
Voici un premier bout de code écrit en juillet dernier par votre serviteur :
val iban="FR7630057410821012122045021" iban.zipWithIndex.map{p=>p match{case(t,idx) if (idx+1)%4==0=>{print(t+" ")} ; case(t,idx)=>{print(t)}}} // si, si ça marche
Et voici le même code après avoir lu la doc et aussi après avoir vu un email sur la liste du Scala User Group :
for(p < - iban.sliding(4,4).toList){ print(p+" ")}
Conclusion : lisez la documentation avant de vous lancer dans des "expérimentations" pour dire ensuite "dans skala' c'est compliqué".
0 no like
Sinon tu peux aussi faire 😉
iban.sliding(4,4).map( _+ " " ).foreach( print )
Le meme sans l’espace a la fin:
println(iban.sliding(4,4).reduceRight(_+" "+_))
Ok alors tant qu’a faire
print( iban.sliding(4,4).mkString( " " ) )
Il n’y a pas a dire, le code review ca paie 🙂
Encore plus simple:
print(iban.sliding(4,4).mkString( » « ))
Damn, grille le temps de lire l’article…
Et le gars qui connaît Guava :
System.out.println( Joiner.on(\' \').join( Splitter.fixedLength(4).split(\"FR7630057410821012122045021\")) );
Et un développeur, même junior, n\’a pas besoin de 6 mois de formation pour arriver à écrire ce code.
Moi je dis ça…
Ouep, pas bête de montrer aussi la version Java.
Et en Groovy ? Là je suis pas chaud mais ça doit être facile je pense
Intéressant! En scala on peut toujours faire des choses simples, et très jolies (très expressives quoi).
Le seul danger c’est surement que des mecs un peu « chauds » nous pondent des API beaucoup plus tordus pour profiter de toutes les subtilités du langage…
@Nicolas A ce propos que penses tu de l’API Anorm de Play? Pour une fois je vais critiquer Play (version Scala), je la trouve hyper compliquée avec tout ses « hiéroglyphes » dès qu’on veut faire un truc un peu poussé…
@Loic la version actuelle d’Anorm avec les parsers combinators est puissante, mais trop compliquée. Ils travaillent sur une version plus simple pour Play 2.0. Moi je m’y suis habitué, j’ai bossé 5 mois avec et c’est facile. Il faut apprendre le principe des « parser combinators » mais rien de méchant. Il faudrait que je fasse un article sur ce sujet car c’est très riche.
La version en Groovy mais ce n’est pas la plus évidente :
iban.split("(?<=\\G.{4})").join(" ")
Cool c’est une super nouvelle qu’ils simplifient un peu ça!
Un article sur ce sujet serait très intéressant en tout cas.
En tout cas, je salue le jeu de mot à la fin… si jeu de mot il y a bien… 😉
Une autre variante Groovy mais pas non plus vraiment la plus claire 🙂 (et nécessite une deuxieme variable (output))
iban.eachMatch(/.{4}/){output=output+ »${it} « }
Avec les balises code, c’est mieux
iban.eachMatch(/.{4}/) {output=output+"${it} "}
Pareil en clojure,
on écrit du code les 1ères semaines et 3 mois plus tard on se rend compte que l’on était un vrai novice 🙂
(->> "FR7630057410821012122045021" (partition-all 4) (interpose " ") (flatten) (apply str))
Et voilà pour PHP :
echo implode(" ",str_split($iban,4));
On va oublier la première version de Nicolas, mais ça nous laisse quand même
1 for(p < - iban.sliding(4,4).toList){ print(p+" ")} 2 iban.sliding(4,4).map( _+ " " ).foreach( print ) 3 println(iban.sliding(4,4).reduceRight(_+" "+_)) 4 print( iban.sliding(4,4).mkString( " " ) )
4 manières différentes d'exprimer la même chose dans le même langage, ça doit pas aider pour travailler en équipe ou maintenir le code.
Je me demande si c'est parce que les librairies de scala sont mal pensées, ou si le problème vient du paradigme fonctionnel ?
Et que tout ceux qui voudraient en conclure que scala c\’est compliqué se demandent d\’abord s\’il y a une façon unique de faire une telle chose dans leur langage de prédilection… Et combien même, je ne suis pas certain que cela serait une bonne chose!
++
« There is more than one way to do it » c’est le moto de perl un langage qui n’est pas réputé pour sa lisibilité ou sa maintenabilité.
« There’s Only One Way To Do It » c’est le moto de python un langage qui a quand même meilleure réputation.
Maintenant chacun est libre d’en conclure ce qu’il veut à propos de scala.
Pour Guava, il faut avoir eu connaissance de cette librairie parmi Apache-Commons et autres, savoir l’integrer, connaitre les API quelle propose …
De plus Splitter ne fonctionne que pour les String (ou charSequence) alors que :A](Int,Int):GroupedIterator[B] »>sliding fonctionnera sur tout Iterator et pourra donc resservir.
Je connaissais déjà la fonction sliding pour l’avoir utilisé sur des Lists.
Il y aura un espace en trop à la fin dans les différentes versions proposées. Et d’un point de vu purement on fonctionnel, le mieux c’est de générer la string finale, puis de l’afficher (effets de bord…). Du coup j’aurais une préférence pour un :
println(iban.sliding(4,4).mkString("", " ", ""))
C’est fou ca, à chaque fois qu’on parle de Scala, on en arrive au vieux debat du « mon langage pisse plus loin que le tiens ». Il va falloir inventer une variante de la loi Godwin pour les langages…
@Alexis A part Aurelien qui trolle un peu, chacun a juste exposé de manière sympathique et ludique la version de chaque language. J’ai trouvé ca très intéressant et je pense que personne ne voulait pisser le plus loin, ca serait bien triste sinon et pas digne d’un dev 😉
Pour la version Groovy, mon premier réfléxe était un simple coup de replaceAll :
def iban = "FR7630057410821012122045021" println iban.replaceAll('(.{4})', '$1 ')
Il n’y a pas d’espace à la fin comme dans certaines de ces solutions, et surtout… ben replaceAll c’est une méthode de java.lang.String 🙂
Pourquoi ne pas utiliser .grouped(4) au lieu de .sliding(4,4), je crois que c’est fait pour ça. Ce qui donne
print(iban.grouped(4).mkString(" ")
et hop une 5eme variante !
@guillaume tu triches, tu connais les expressions régulière 😉 http://xkcd.com/208/
@Fabrice Croiseaux bien vu ! et visiblement c’est le meme code en dessous
def grouped[B >: A](size: Int): GroupedIterator[B] = new GroupedIterator[B](self, size, size)
et
def sliding[B >: A](size: Int, step: Int = 1): GroupedIterator[B] = new GroupedIterator[B](self, size, step)
La version la plus lisible serait pour moi au final
for(p < – iban.grouped(4).toList){ print(p+" ")}
ou
iban.grouped(4).map( _+ " " ).foreach( print )
@Aurélien Pelletier je connais pas bien python mais en tout cas que je soit Java ou Groovy il n'y a pas une unique façon de faire cette opération…
Du moment que tu as des API riches sur la manipulation des chaines et des collections tu trouveras toujours plusieurs moyens de faire ce genre de choses
@Aurelien Enfin quand même en Java tu peux aussi écrire ce code différemment, les débutants ne connaissent même pas tous les features de Java standard, alors qund tu ajoutes les commons-collection et guava tu te retrouves avec du code très varie, donc il y a exactement le même problème d’homogénéité dans l’écosystème.
Ce qui est important ce n’est pas la concision du code, c’est sa lisibilité et sa maintenabilité. En Java comme en Scala comme pour tous les langages, et ça franchement c’est aussi le boulot du développeur. Si c’est un newbie, qui sort de l’école et qui n’a fait que des projets jetables, il faut l’amener a ces considérations.
Ben justement, des trucs qui s’appellent Splitter et Joiner me paraissent plus explicites qu’une méthode « sliding ». Toutes considérations de langages mises à part.
Sinon j’aime bien la version de Guillaume aussi 🙂
Apres avec du Java/Guava on peut aussi splitter la list en sous listes de 4 elements:
Iterables.partition( iban.toCharArray() , 4 );
Au final tous les langages permettent de faire a peu près la même chose sauf que forcement les nouveaux langages s’inspirent du passé et proposent plus de choses nativement… Y a qu’a voir toutes ces librairies java (dont apache commons) qui n’utilisent toujours pas les generics…
Au final rien ne vous empêche de contribuer sur les libs Java 😀
Et en Haskell :
byFour :: [Char] -> [Char]
byFour (a:b:c:d:xs) = [a,b,c,d,’ ‘] ++ byFour xs
byFour x = x
Je trouve ça plus lisible que la version Scala :
for(p < – iban.sliding(4,4).toList){ print(p+" ")}
Le but de l’exercice c’est de résoudre le problème avec les primitives du langage, ou, à la limite, les quelques classes de base. A priori, sortir une librairie externe, que ce soit guava ou apache commons, ça sort un peu des clous.
+1 à la version regexp + groovy 😉
@fredb : le jour ou l’iban est sur un multiple de 4, la solution Groovy générera un bug 🙂
A propos de la conclusion de l’article c’est évident qu’il faut lire la documentation, et cette conclusion pourrait être faite pour n’importe quel langage.
fun([A, B, C, D|Rest)->[A, B, C, D, $\s|fun(Rest)];
fun(Rest)->Rest;
Comme en Haskell, quoi 🙂
Ou bien :
I= »FR7630057410821012122045021″.
lists:reverse ( lists:foldl(fun(Char, Acc)->
case length(Acc) rem 5 of
4 -> [Char, $\s|Acc];
_ -> [Char|Acc]
end
end, [], I)).
La fonction rem :reste de la division..
On accumule tous les caractères, tous les 4 on rajoute un \s (qui veut dire universellement « espaaace »)
Et une fois la chaîne de caractères obtenue par accumulation en tête de la liste, on retourne cette liste (lists:reverse).
Je crois que c’est clair 😀
C’est gentil toutes ces variantes…
Mais elles nous font combien de cycles horloge?
C’est une autre poésie… je sais, je sais