web-dev-qa-db-fra.com

Dernière itération de for for amélioré en java

Existe-t-il un moyen de déterminer si la boucle effectue une itération pour la dernière fois? Mon code ressemble à ceci:

int[] array = {1, 2, 3...};
StringBuilder builder = new StringBuilder();

for(int i : array)
{
    builder.append("" + i);
    if(!lastiteration)
        builder.append(",");
}

Maintenant, le problème est que je ne veux pas ajouter la virgule à la dernière itération. Y at-il maintenant un moyen de déterminer si c'est la dernière itération ou si je suis bloqué avec la boucle for ou en utilisant un compteur externe pour garder une trace.

130
Mercurious

Une autre solution consiste à ajouter la virgule avant l'annexe i, mais pas sur la première itération. (N'utilisez pas "" + i, au fait - vous ne voulez pas vraiment la concaténation ici, et StringBuilder a une excellente surcharge (int (surcharge) append.)

int[] array = {1, 2, 3...};
StringBuilder builder = new StringBuilder();

for (int i : array) {
    if (builder.length() != 0) {
        builder.append(",");
    }
    builder.append(i);
}

La bonne chose à ce sujet est que cela fonctionnera avec toutes les variables Iterable - vous ne pouvez pas toujours indexer les choses. ("Ajouter la virgule puis la supprimer à la fin" est une bonne suggestion lorsque vous utilisez réellement StringBuilder - mais cela ne fonctionne pas pour des tâches telles que l'écriture dans des flux. C'est probablement la meilleure approche pour résoudre ce problème. )

216
Jon Skeet

Une autre façon de faire ceci:

String delim = "";
for (int i : ints) {
    sb.append(delim).append(i);
    delim = ",";
}

Mise à jour: Pour Java 8, vous avez maintenant Collectors

141
toolkit

Il serait peut-être plus facile de toujours ajouter. Et ensuite, lorsque vous avez terminé votre boucle, supprimez simplement le dernier caractère. Des tonnes moins de conditions de cette façon aussi.

Vous pouvez utiliser la fonction StringBuilder 's deleteCharAt(int index) avec index étant length() - 1

39
Dinah

Peut-être que vous utilisez le mauvais outil pour le travail.

C’est plus manuel que ce que vous faites mais c’est plus élégant, sinon un peu "old school"

 StringBuffer buffer = new StringBuffer();
 Iterator iter = s.iterator();
 while (iter.hasNext()) {
      buffer.append(iter.next());
      if (iter.hasNext()) {
            buffer.append(delimiter);
      }
 }
29
Omar Kooheji

C'est presque une répétition de cette question de StackOverflow . Ce que vous voulez, c'est StringUtils et appeler la méthode join.

StringUtils.join(strArr, ',');
15
Phil H

Une autre solution (peut-être la plus efficace)

    int[] array = {1, 2, 3};
    StringBuilder builder = new StringBuilder();

    if (array.length != 0) {
        builder.append(array[0]);
        for (int i = 1; i < array.length; i++ )
        {
            builder.append(",");
            builder.append(array[i]);
        }
    }
14
bruno conde

Les boucles explicites fonctionnent toujours mieux que les boucles implicites.

builder.append( "" + array[0] );
for( int i = 1; i != array.length; i += 1 ) {
   builder.append( ", " + array[i] );
}

Vous devriez envelopper le tout dans une instruction if, au cas où vous auriez affaire à un tableau de longueur nulle.

6
S.Lott

restez simple et utilisez un standard pour loop:

for(int i = 0 ; i < array.length ; i ++ ){
    builder.append(array[i]);
    if( i != array.length - 1 ){
        builder.append(',');
    }
}

ou utilisez simplement Apache commons-lang StringUtils.join ()

5
Gareth Davis

Si vous le convertissez en une boucle d'index classique, oui.

Ou vous pouvez simplement supprimer la dernière virgule une fois que c'est fait. Ainsi:

int[] array = {1, 2, 3...};
StringBuilder

builder = new StringBuilder();

for(int i : array)
{
    builder.append(i + ",");
}

if(builder.charAt((builder.length() - 1) == ','))
    builder.deleteCharAt(builder.length() - 1);

Moi, je viens d'utiliser StringUtils.join() from commons-lang .

4
sblundy

Basé sur Java.util.AbstractCollection.toString (), il se ferme tôt pour éviter le délimiteur.

StringBuffer buffer = new StringBuffer();
Iterator iter = s.iterator();
for (;;) {
  buffer.append(iter.next());
  if (! iter.hasNext())
    break;
  buffer.append(delimiter);
}

C'est efficace et élégant, mais pas aussi évident que certaines des autres réponses.

3
13ren

Vous avez besoin de Class Separator .

Separator s = new Separator(", ");
for(int i : array)
{
     builder.append(s).append(i);
}

L'implémentation de la classe Separator est simple. Il encapsule une chaîne renvoyée à chaque appel de toString(), à l'exception du premier appel, qui renvoie une chaîne vide.

3
akuhn

Voici une solution:

int[] array = {1, 2, 3...};
StringBuilder builder = new StringBuilder();
bool firstiteration=true;

for(int i : array)
{
    if(!firstiteration)
        builder.append(",");

    builder.append("" + i);
    firstiteration=false;
}

Cherchez la première itération:)

2
FallenAvatar

Encore une autre option.

StringBuilder builder = new StringBuilder();
for(int i : array)
    builder.append(',').append(i);
String text = builder.toString();
if (text.startsWith(",")) text=text.substring(1);
1
Peter Lawrey

Bon nombre des solutions décrites ici sont un peu excessives, à mon humble avis, en particulier celles qui reposent sur des bibliothèques externes. Il existe un joli langage clair et clair permettant d’obtenir une liste séparée par des virgules que j’ai toujours utilisée. Il repose sur l'opérateur conditionnel (?):

Edit : Solution originale correcte, mais non optimale selon les commentaires. Essayer une seconde fois:

    int[] array = {1, 2, 3};
    StringBuilder builder = new StringBuilder();
    for (int i = 0 ;  i < array.length; i++)
           builder.append(i == 0 ? "" : ",").append(array[i]); 

Voilà, en 4 lignes de code incluant la déclaration du tableau et le StringBuilder.

1
Julien Chastang

Comme mentionné dans la boîte à outils, Java 8 contient maintenant Collectors . Voici à quoi ressemblerait le code:

String joined = array.stream().map(Object::toString).collect(Collectors.joining(", "));

Je pense que cela correspond exactement à ce que vous recherchez et vous pouvez utiliser ce modèle pour de nombreuses autres choses.

1
b1tw153

Voici un point de repère SSCCE que j'ai exécuté (en rapport avec ce que je devais mettre en œuvre) avec ces résultats: 

elapsed time with checks at every iteration: 12055(ms)
elapsed time with deletion at the end: 11977(ms)

Sur mon exemple au moins, ignorer la vérification à chaque itération n’est pas sensiblement plus rapide, surtout pour les volumes de données sains, mais il est plus rapide.

import Java.util.ArrayList;
import Java.util.List;


public class TestCommas {

  public static String GetUrlsIn(int aProjectID, List<String> aUrls, boolean aPreferChecks)
  {

    if (aPreferChecks) {

      StringBuffer sql = new StringBuffer("select * from mytable_" + aProjectID + " WHERE hash IN ");

      StringBuffer inHashes = new StringBuffer("(");
      StringBuffer inURLs = new StringBuffer("(");

      if (aUrls.size() > 0)
      {

      for (String url : aUrls)
      {

        if (inHashes.length() > 0) {
        inHashes.append(",");
        inURLs.append(",");
        }

        inHashes.append(url.hashCode());

        inURLs.append("\"").append(url.replace("\"", "\\\"")).append("\"");//.append(",");

      }

      }

      inHashes.append(")");
      inURLs.append(")");

      return sql.append(inHashes).append(" AND url IN ").append(inURLs).toString();
    }

    else {

      StringBuffer sql = new StringBuffer("select * from mytable" + aProjectID + " WHERE hash IN ");

      StringBuffer inHashes = new StringBuffer("(");
      StringBuffer inURLs = new StringBuffer("(");

      if (aUrls.size() > 0)
      {

      for (String url : aUrls)
      {
        inHashes.append(url.hashCode()).append(","); 

        inURLs.append("\"").append(url.replace("\"", "\\\"")).append("\"").append(",");
      }

      }

      inHashes.deleteCharAt(inHashes.length()-1);
      inURLs.deleteCharAt(inURLs.length()-1);

      inHashes.append(")");
      inURLs.append(")");

      return sql.append(inHashes).append(" AND url IN ").append(inURLs).toString();
    }

  }

  public static void main(String[] args) { 
        List<String> urls = new ArrayList<String>();

    for (int i = 0; i < 10000; i++) {
      urls.add("http://www.google.com/" + System.currentTimeMillis());
      urls.add("http://www.yahoo.com/" + System.currentTimeMillis());
      urls.add("http://www.bing.com/" + System.currentTimeMillis());
    }


    long startTime = System.currentTimeMillis();
    for (int i = 0; i < 300; i++) {
      GetUrlsIn(5, urls, true);
    }
    long endTime = System.currentTimeMillis();
    System.out.println("elapsed time with checks at every iteration: " + (endTime-startTime) + "(ms)");

    startTime = System.currentTimeMillis();
    for (int i = 0; i < 300; i++) {
      GetUrlsIn(5, urls, false);
    }
    endTime = System.currentTimeMillis();
    System.out.println("elapsed time with deletion at the end: " + (endTime-startTime) + "(ms)");
  }
}
1
Buffalo

Une autre approche consiste à stocker la longueur du tableau (si disponible) dans une variable séparée (plus efficace que de vérifier à nouveau la longueur à chaque fois). Vous pouvez ensuite comparer votre index à cette longueur pour déterminer si vous souhaitez ou non ajouter la virgule finale.

ÉDITER: une autre considération est de comparer le coût de performance de la suppression d’un dernier caractère (pouvant entraîner une copie de chaîne) à la vérification d’un conditionnel à chaque itération.

0
Brian

Deux chemins alternatifs ici:

1: Apache Commons String Utils

2: Conservez un booléen appelé first, défini sur true. Dans chaque itération, si first est faux, ajoutez votre virgule; Après cela, définissez first sur false.

0
Paul Brinkley

Dans ce cas, il n’est vraiment pas nécessaire de savoir s’il s’agit de la dernière répétition ..__ Il existe de nombreuses façons de résoudre ce problème. Une façon serait:

String del = null;
for(int i : array)
{
    if (del != null)
       builder.append(del);
    else
       del = ",";
    builder.append(i);
}
0
fastcodejava

Puisque c'est un tableau fixe, il serait plus facile d'éviter simplement les améliorations pour ... Si l'objet est une collection, un itérateur serait plus facile.

int nums[] = getNumbersArray();
StringBuilder builder = new StringBuilder();

// non enhanced version
for(int i = 0; i < nums.length; i++){
   builder.append(nums[i]);
   if(i < nums.length - 1){
       builder.append(",");
   }   
}

//using iterator
Iterator<int> numIter = Arrays.asList(nums).iterator();

while(numIter.hasNext()){
   int num = numIter.next();
   builder.append(num);
   if(numIter.hasNext()){
      builder.append(",");
   }
}
0
AnthonyJClink

Si vous ne faites que transformer un tableau en un tableau délimité par des virgules, de nombreuses langues ont une fonction de jointure pour cela. Il transforme un tableau en une chaîne avec un séparateur entre chaque élément.

0
Dinah