Dernière itération de la boucle améliorée en java
Est-il un moyen de déterminer si la boucle est 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 truc c'est que je ne veux pas ajouter la virgule dans la dernière itération. Maintenant, il y a un moyen de déterminer si c'est la dernière itération ou si je suis coincé avec la boucle for ou en utilisant un compteur externe pour garder la trace.
21 réponses
une autre alternative est d'ajouter la virgule avant d'ajouter i, mais pas sur la première itération. (S'il vous plaît ne pas utiliser "" + i
, soit dit en passant - vous ne voulez pas vraiment concaténation ici, et StringBuilder a une surcharge d'ajout (int) parfaitement bonne.)
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 à propos de ceci est qu'il fonctionnera avec n'importe quel Iterable
- vous ne pouvez pas toujours indexer les choses. ("Ajouter la virgule, puis l'enlever à la fin" est une belle suggestion lorsque vous utilisez vraiment StringBuilder - mais cela ne fonctionne pas pour des choses comme écrire à streams. C'est peut-être la meilleure approche pour ce problème précis.)
une autre façon de le faire:
String delim = "";
for (int i : ints) {
sb.append(delim).append(i);
delim = ",";
}
mise à jour: pour Java 8, Vous avez maintenant Collectors
Il pourrait être plus facile de toujours ajouter. Et puis, quand vous avez fini avec votre boucle, il suffit de supprimer le caractère final. Des tonnes de moins de conditionnels.
vous pouvez utiliser StringBuilder
's deleteCharAt(int index)
avec l'index étant length() - 1
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 si pas un peu "vieille école"
StringBuffer buffer = new StringBuffer();
Iterator iter = s.iterator();
while (iter.hasNext()) {
buffer.append(iter.next());
if (iter.hasNext()) {
buffer.append(delimiter);
}
}
c'est presque une répétition de cette question sur L'écoulement des piles . Ce que vous voulez est StringUtils , et d'appeler le joindre méthode.
StringUtils.join(strArr, ',');
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]);
}
}
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 un if-statement juste au cas où vous avez affaire à un tableau de longueur zéro.
keep it simple et l'utilisation d'un standard pour la boucle:
for(int i = 0 ; i < array.length ; i ++ ){
builder.append(array[i]);
if( i != array.length - 1 ){
builder.append(',');
}
}
ou tout simplement utiliser apache commons-lang StringUtils.join ()
si vous le convertissez en boucle d'index classique, Oui.
ou vous pouvez supprimer la dernière virgule après que c'est fait. Comme ceci:
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()
à partir de commons-lang .
Vous avez besoin de Classe Séparateur .
Separator s = new Separator(", ");
for(int i : array)
{
builder.append(s).append(i);
}
l'application de la classe Separator
est simple. Il enroule une corde qui est retournée sur chaque appel de toString()
sauf pour le premier appel, qui renvoie une corde vide.
basé sur java.util.AbstractCollection.toString (), il sort 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 certains des autres réponses.
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;
}
rechercher la première itération :)
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);
beaucoup des solutions décrites ici sont un peu exagérées, IMHO, surtout celles qui s'appuient sur des bibliothèques externes. Il y a un beau langage propre et clair pour réaliser une liste séparée par des virgules que j'ai toujours utilisée. Elle repose sur le conditionnel (?) exploitant:
Edit : solution originale correcte, mais non optimale selon les commentaires. Essayer une deuxième 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 y compris la déclaration du tableau et du StringBuilder.
voici un benchmark SSCCE que j'ai fait (lié à ce que j'ai dû 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, sauter le contrôle à chaque itération n'est pas sensiblement plus rapide en particulier pour les volumes sains de données, 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)");
}
}
comme toolkit mentionné, en Java 8 nous avons maintenant Collectors . Voici à quoi ressemblerait le code:
String joined = array.stream().map(Object::toString).collect(Collectors.joining(", "));
je pense que c'est exactement ce que vous cherchez, et c'est un motif que vous pourriez utiliser pour beaucoup d'autres choses.
une autre approche consiste à stocker la longueur du tableau (si disponible) dans une variable distincte (ce qui est plus efficace qu'une nouvelle vérification de la longueur à chaque fois). Vous pouvez ensuite comparer votre index à cette longueur pour déterminer s'il faut ajouter ou non la virgule finale.
éditer: une autre considération est de peser le coût de performance d'enlever un caractère final (qui peut causer une copie de chaîne de caractères) contre avoir un conditionnel être vérifié dans chaque itération.
si vous transformez seulement un tableau en un tableau délimité par une virgule, Beaucoup de langues ont une fonction jointure pour exactement cela. Il transforme un tableau en chaîne avec un délimiteur entre chaque élément.
Dans ce cas, il n'y a vraiment pas besoin de savoir si c'est la dernière répétition. Il existe de nombreuses façons que nous pouvons résoudre ce problème. Une solution serait:
String del = null;
for(int i : array)
{
if (del != null)
builder.append(del);
else
del = ",";
builder.append(i);
}
deux chemins alternatifs ici:
1: Apache Commons String Utils
2: garder un booléen appelé first
, placé à true. Dans chaque itération, si first
est false, ajoutez votre virgule; après cela, mettez first
à false.
depuis son un tableau fixe, il serait plus facile tout simplement d'éviter le rehaussé pour... Si l'Objet est une collection d'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(",");
}
}