Comment enlever les caractères répétés d'un String en java?
Résolu/Fermé
dvmedellin
Messages postés
4
Date d'inscription
lundi 26 novembre 2012
Statut
Membre
Dernière intervention
17 décembre 2012
-
26 nov. 2012 à 18:03
bizu53 Messages postés 1274 Date d'inscription samedi 30 août 2008 Statut Membre Dernière intervention 21 juin 2015 - 30 nov. 2012 à 20:55
bizu53 Messages postés 1274 Date d'inscription samedi 30 août 2008 Statut Membre Dernière intervention 21 juin 2015 - 30 nov. 2012 à 20:55
A voir également:
- Comment enlever les caractères répétés d'un String en java?
- Waptrick java football - Télécharger - Jeux vidéo
- Jeux java itel football - Télécharger - Jeux vidéo
- Caractères ascii - Guide
- Caractères spéciaux clavier azerty - Guide
- Java apk - Télécharger - Langages
4 réponses
voila le code correspondant :
Edition du bug.
String s = "abcdefdged"; for(int i=0; i<s.length();i++) { for(int j=0; j<s.length();j++) { if(i<s.length() && j<s.length() && i!=j && s.charAt(i)==s.charAt(j)) { int index = s.indexOf(s.charAt(i),s.indexOf(s.charAt(i))+1); s = s.substring(0, index)+s.substring(index+1,s.length()); } } } System.out.println(s);
Edition du bug.
dvmedellin
Messages postés
4
Date d'inscription
lundi 26 novembre 2012
Statut
Membre
Dernière intervention
17 décembre 2012
1
27 nov. 2012 à 23:41
27 nov. 2012 à 23:41
En effet, ma question est tres scolaire parce que je suis a l'école... les variables que j'ai donné sont un exemple, et le code est une methode, ce n'est pas le code de \\main.
En essayant, je suis parvenu a un code simple a mon avis; vous pourrez peut-être me dire ce que vous en pensez:
public static String pasDeDoubles(String ch) {
ch = newString(s);
String result = new String("")
for (int i = 0; i < ch.length(); i++) {
if (!result.contains(ch.charAt(i))) {
result = result + ch.charAt(i);
}
}
return result;
}
En essayant, je suis parvenu a un code simple a mon avis; vous pourrez peut-être me dire ce que vous en pensez:
public static String pasDeDoubles(String ch) {
ch = newString(s);
String result = new String("")
for (int i = 0; i < ch.length(); i++) {
if (!result.contains(ch.charAt(i))) {
result = result + ch.charAt(i);
}
}
return result;
}
KX
Messages postés
16752
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
31 août 2024
3 019
28 nov. 2012 à 00:53
28 nov. 2012 à 00:53
Il faudrait l'écrire en Java correct pour que ça compile, mais algorithmiquement ça fait ce qu'il faut.
Après côté performance, ce n'est pas terrible, mais c'est principalement à cause de la construction des String successifs result = result + ch.charAt(i).
Après côté performance, ce n'est pas terrible, mais c'est principalement à cause de la construction des String successifs result = result + ch.charAt(i).
dvmedellin
Messages postés
4
Date d'inscription
lundi 26 novembre 2012
Statut
Membre
Dernière intervention
17 décembre 2012
1
28 nov. 2012 à 04:27
28 nov. 2012 à 04:27
on pourrait prendre un StringBuilder, j'imagine... mais dans le cours... on est pas rendu la (je commence la)
KX
Messages postés
16752
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
31 août 2024
3 019
26 nov. 2012 à 18:17
26 nov. 2012 à 18:17
Techniquement, on ne peux pas "enlever" des caractères, car un String n'est pas modifiable, chaque manipulation créé un nouveau String, cela vient du fait qu'en interne on stocke les caractères dans un tableau qu'on ne peux pas modifier.
La bonne idée serait peut-être de récupérer ce tableau pour faire tes manipulations :
La bonne idée serait peut-être de récupérer ce tableau pour faire tes manipulations :
String str = "abcdefdge"; char[] tab = s.toCharArray(); // ... String res = new String(tab,offset,count);
bizu53
Messages postés
1274
Date d'inscription
samedi 30 août 2008
Statut
Membre
Dernière intervention
21 juin 2015
860
Modifié par bizu53 le 27/11/2012 à 20:37
Modifié par bizu53 le 27/11/2012 à 20:37
Je ferais tout simplement :
Explication (au cas où) de mon code :
Un Set ne contient qu'un seul exemplaire des objets qu'il contient.
La méthode add retourne true s'il le Set a été modifié, donc, en parcourant les caractères, si le caractère n'a pas déjà été vu.
S'il n'était pas dans l'ensemble (donc "nouveau"), on l'ajoute au StringBuilder.
Une seule boucle for, une seule if (et aucune condition dans tous les sens pour vérifier les index ou que sais-je). Je ne pense pas qu'on puisse faire plus simple et efficace.
Au passage, je conseille l'utilisation d'un StringBuilder (ou StringBuffer si nécessaire) plutôt que, comme KX le suggère, travailler directement sur le char[] (même si au final ça y revient, l'essentiel étant de ne pas construire plein de String).
final String s = "abcdefdged"; final Set<Character> set = new HashSet<>(); final StringBuilder sb = new StringBuilder(); for (final char c : s.toCharArray()) { if (set.add(c)) { sb.append(c); } } System.out.println(sb);
Explication (au cas où) de mon code :
Un Set ne contient qu'un seul exemplaire des objets qu'il contient.
La méthode add retourne true s'il le Set a été modifié, donc, en parcourant les caractères, si le caractère n'a pas déjà été vu.
S'il n'était pas dans l'ensemble (donc "nouveau"), on l'ajoute au StringBuilder.
Une seule boucle for, une seule if (et aucune condition dans tous les sens pour vérifier les index ou que sais-je). Je ne pense pas qu'on puisse faire plus simple et efficace.
Au passage, je conseille l'utilisation d'un StringBuilder (ou StringBuffer si nécessaire) plutôt que, comme KX le suggère, travailler directement sur le char[] (même si au final ça y revient, l'essentiel étant de ne pas construire plein de String).
KX
Messages postés
16752
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
31 août 2024
3 019
Modifié par KX le 27/11/2012 à 20:59
Modifié par KX le 27/11/2012 à 20:59
"Une seule boucle for, une seule if" mais un String, un Set, et un StringBuilder, ça fait pas mal de données à manipuler, alors oui c'est facile à coder, mais ce n'est pas optimisé...
Remarque : c'est quand même un peu mieux que la méthode proposée par Flog78.
J'ai fait quelques tests de comparaison, voici ce que ça donne (j'en profite pour mettre ma proposition)
Remarque : c'est quand même un peu mieux que la méthode proposée par Flog78.
J'ai fait quelques tests de comparaison, voici ce que ça donne (j'en profite pour mettre ma proposition)
import java.util.HashSet; import java.util.Random; import java.util.Set; public class Test { public static void main(String[] args) { int n = 1000000; Random random = new Random(); for (int j=0; j<10; j++) { double n_Flog78=0, n_KX=0, n_bizu53=0; long n1,n2,n3,n4; for (int i=0; i<n; i++) { // mot aléatoire d'environ 7.93 caractères hexadécimaux dont 1.52 doublons String s = Integer.toHexString(random.nextInt()); String r; n1 = System.nanoTime(); { r = test_Flog78(s); } n2 = System.nanoTime(); { r = test_bizu53(s); } n3 = System.nanoTime(); { r = test_KX(s); } n4 = System.nanoTime(); n_Flog78 += (n2-n1); n_bizu53 += (n3-n2); n_KX += (n4-n3); } System.out.printf("Temps moyens :\tFlog 78 = %.1f ns\tbizu53 = %.1f ns\tKX = %.1f ns\n", n_Flog78/n, n_bizu53/n, n_KX/n); } } public static String test_Flog78(String s) { for(int i=0; i<s.length();i++) { for(int j=0; j<s.length();j++) { if(i<s.length() && j<s.length() && i!=j && s.charAt(i)==s.charAt(j)) { int index = s.indexOf(s.charAt(i),s.indexOf(s.charAt(i))+1); s = s.substring(0, index)+s.substring(index+1,s.length()); } } } return s; } public static String test_bizu53(String s) { final Set<Character> set = new HashSet<Character>(); final StringBuilder sb = new StringBuilder(); for (final char c : s.toCharArray()) { if (set.add(c)) { sb.append(c); } } return sb.toString(); } public static String test_KX(String str) { char[] tab = str.toCharArray(); int count = tab.length; for (int i=0; i<count; i++) for (int j=i+1; j<count; j++) if (tab[j]==tab[i]) tab[j--] = tab[--count]; return new String(tab,0,count); } }
bizu53
Messages postés
1274
Date d'inscription
samedi 30 août 2008
Statut
Membre
Dernière intervention
21 juin 2015
860
Modifié par bizu53 le 27/11/2012 à 21:14
Modifié par bizu53 le 27/11/2012 à 21:14
Je n'ai pas prétendu que c'était la solution la plus performante :).
C'est juste la plus simple : On voit directement ce qu'elle fait (à condition de simplement connaître la méthode add d'un Set). La plus maintenable.
(edit: et non, pas de String à part l'inévitable de la fin)
C'est juste la plus simple : On voit directement ce qu'elle fait (à condition de simplement connaître la méthode add d'un Set). La plus maintenable.
(edit: et non, pas de String à part l'inévitable de la fin)
KX
Messages postés
16752
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
31 août 2024
3 019
27 nov. 2012 à 21:31
27 nov. 2012 à 21:31
"Je ne pense pas qu'on puisse faire plus simple et efficace."
"Je n'ai pas prétendu que c'était la solution la plus performante :)"
Pour moi l'efficacité et la performance c'est quand même très proche ;-)
En fait je proposais la méthode des tableaux parce que la question de dvmedellin est très scolaire et les Collection ne font surement pas (encore) partie de ses compétences...
Mais sinon je suis d'accord, d'un point de vue lisibilité du code, les Set sont une bonne idée.
"Je n'ai pas prétendu que c'était la solution la plus performante :)"
Pour moi l'efficacité et la performance c'est quand même très proche ;-)
En fait je proposais la méthode des tableaux parce que la question de dvmedellin est très scolaire et les Collection ne font surement pas (encore) partie de ses compétences...
Mais sinon je suis d'accord, d'un point de vue lisibilité du code, les Set sont une bonne idée.
bizu53
Messages postés
1274
Date d'inscription
samedi 30 août 2008
Statut
Membre
Dernière intervention
21 juin 2015
860
Modifié par bizu53 le 27/11/2012 à 21:44
Modifié par bizu53 le 27/11/2012 à 21:44
Effectivement mon "efficace" était sujet à interprétation.
Je le disais dans le sens où ce code, court, est suffisant pour se prémunir contre d'éventuels bugs (d'index ou autres).
Je le disais dans le sens où ce code, court, est suffisant pour se prémunir contre d'éventuels bugs (d'index ou autres).
bizu53
Messages postés
1274
Date d'inscription
samedi 30 août 2008
Statut
Membre
Dernière intervention
21 juin 2015
860
29 nov. 2012 à 22:18
29 nov. 2012 à 22:18
J'ai envie d'ajouter mon grain de sel (et de poivre, attention à ne pas le croquer) maintenant qu'on a la solution du questionneur. Bien évidemment, il ne s'agit là que d'un exercice, mais j'ajoute ce commentaire pour ne pas laisser l'envie à certains lecteurs de mesurer la performance d'un code comme tu le fais : Ça ne se mesure pas au temps d'exécution sur quelques exemples, mais avec une (au moins minimale) analyse de sa complexité (dès qu'on sait ce que c'est).
Un code qui est quasi "instantané" dans quelques conditions favorables mais qui est lent (voire très) dès qu'on les perd n'est, pour moi, pas un code "efficace" (même s'il est lisible etc.). Bien évidemment je ne préjuge de rien, tu aurais peut-être ou sûrement proposé un autre code si tu avais voulu (ou pensé à) gérer des entrées de taille quelconque (plus longues).
Ton code tout comme celui de Flog78 et de dvmedellin nécessitent plein de parcours (plus ou moins entiers) des caractères quand le mien n'en nécessite qu'un seul et unique. Le code de dvmedellin nécessite aussi plusieurs parcours (l'inévitable + ceux provoqués par contains() / indexOf()) mais sur le résultat en construction, donc toujours plus court (voire beaucoup plus court) que l'entrée, et grandissant peu vite de manière générale, ce qui est efficace également.
Je complète ton test, en considérant différentes tailles et en y incluant la solution de dvmedellin (je l'ai retouchée mais elle est quasiment telle qu'il l'a faite, et j'en ai fait 2 versions sans String à part la finale pour le résultat) ... et d'aller voir ce qu'il se passe dès qu'on passe les 100 caractères environ entre ta version sans String et sa version bourrée de Strings => comme quoi c'est plus l'algorithme qui compte que la façon de faire.
(Le fait que ce soit un exercice ne dispense pas d'y trouver des ouvertures, d'où mes remarques :))
Un code qui est quasi "instantané" dans quelques conditions favorables mais qui est lent (voire très) dès qu'on les perd n'est, pour moi, pas un code "efficace" (même s'il est lisible etc.). Bien évidemment je ne préjuge de rien, tu aurais peut-être ou sûrement proposé un autre code si tu avais voulu (ou pensé à) gérer des entrées de taille quelconque (plus longues).
Ton code tout comme celui de Flog78 et de dvmedellin nécessitent plein de parcours (plus ou moins entiers) des caractères quand le mien n'en nécessite qu'un seul et unique. Le code de dvmedellin nécessite aussi plusieurs parcours (l'inévitable + ceux provoqués par contains() / indexOf()) mais sur le résultat en construction, donc toujours plus court (voire beaucoup plus court) que l'entrée, et grandissant peu vite de manière générale, ce qui est efficace également.
Je complète ton test, en considérant différentes tailles et en y incluant la solution de dvmedellin (je l'ai retouchée mais elle est quasiment telle qu'il l'a faite, et j'en ai fait 2 versions sans String à part la finale pour le résultat) ... et d'aller voir ce qu'il se passe dès qu'on passe les 100 caractères environ entre ta version sans String et sa version bourrée de Strings => comme quoi c'est plus l'algorithme qui compte que la façon de faire.
private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,;:!?./§*-+="; public static void main(final String[] args) { final int n = 1000; final Random random = new Random(); for (final int length : new int[] { 5, 10, 50, 100, 500, 1000 }) { System.out.printf("---\nlength=%d\n---\n", length); for (int j = 0; j < 30; ++j) { long n1, n2, n3, n4, n5, n6, n7; long n_Flog78 = 0; long n_KX = 0; long n_bizu53 = 0; long n_dvmedellin = 0; long n_dvmedellin_SB = 0; long n_dvmedellin_chars = 0; for (int i = 0; i < n; ++i) { final StringBuilder sb = new StringBuilder(); while (sb.length() < length) { sb.append(CHARACTERS.charAt(random.nextInt(CHARACTERS.length()))); } final String s = sb.toString(); String r; n1 = System.nanoTime(); r = test_Flog78(s); n2 = System.nanoTime(); r = test_bizu53(s); n3 = System.nanoTime(); r = test_KX(s); n4 = System.nanoTime(); r = test_dvmedellin(s); n5 = System.nanoTime(); r = test_dvmedellin_SB(s); n6 = System.nanoTime(); r = test_dvmedellin_chars(s); n7 = System.nanoTime(); n_Flog78 += n2 - n1; n_bizu53 += n3 - n2; n_KX += n4 - n3; n_dvmedellin += n5 - n4; n_dvmedellin_SB += n6 - n5; n_dvmedellin_chars += n7 - n6; } System.out.printf("Temps moyens :" + " Flog78 = %d ns ;" + " bizu53 = %d ns ;" + " KX = %d ns ;" + " dvmedellin = %d ns ;" + " dvmedellin_SB = %d ns ;" + " dvmedellin_chars = %d ns" + "\n", n_Flog78 / n, n_bizu53 / n, n_KX / n, n_dvmedellin / n, n_dvmedellin_SB / n, n_dvmedellin_chars / n); } } } private static String test_Flog78(String s) { for (int i = 0; i < s.length(); i++) { for (int j = 0; j < s.length(); j++) { if (i < s.length() && j < s.length() && i != j && s.charAt(i) == s.charAt(j)) { final int index = s.indexOf(s.charAt(i), s.indexOf(s.charAt(i)) + 1); s = s.substring(0, index) + s.substring(index + 1, s.length()); } } } return s; } private static String test_bizu53(final String s) { final Set<Character> set = new HashSet<Character>(); final StringBuilder sb = new StringBuilder(); for (final char c : s.toCharArray()) { if (set.add(c)) { sb.append(c); } } return sb.toString(); } private static String test_KX(final String str) { final char[] tab = str.toCharArray(); int count = tab.length; for (int i = 0; i < count; i++) { for (int j = i + 1; j < count; j++) { if (tab[j] == tab[i]) { tab[j--] = tab[--count]; } } } return new String(tab, 0, count); } private static String test_dvmedellin(final String s) { String res = ""; for (int i = 0; i < s.length(); i++) { final String c = s.substring(i, i + 1); // je me suis permis de corriger son code de cette manière (on n'est pas à un String près) if (!res.contains(c)) { res += c; } } return res; } private static String test_dvmedellin_SB(final String s) { final StringBuilder res = new StringBuilder(); for (int i = 0; i < s.length(); ++i) { final String c = s.substring(i, i + 1); if (res.indexOf(c) < 0) { res.append(c); } } return res.toString(); } private static String test_dvmedellin_chars(final String s) { final char[] in = s.toCharArray(); final char[] out = new char[CHARACTERS.length()]; // il ne pourra pas y avoir plus de caractères que dans l'ensemble considéré int count = 0; int j; for (int i = 0; i < in.length; ++i) { final char c = in[i]; j = 0; while (j < count && out[j] != c) { ++j; } if (j == count) { out[j] = c; ++count; } } return new String(out, 0, count); }
(Le fait que ce soit un exercice ne dispense pas d'y trouver des ouvertures, d'où mes remarques :))
27 nov. 2012 à 14:35
Par exemple, avec s = "abaa" → java.lang.StringIndexOutOfBoundsException...
En plus l'utilisation des indexOf, et de substring est très compliquée, sans parler de la concaténation de String qui va créer de nouveaux String à chaque fois, alors que la manipulation des caractères dans le tableau comme je le proposais hier est nettement plus propre !
Modifié par Flog78 le 27/11/2012 à 14:46
i<s.length() && j<s.length()