जावा में लूप के लिए बढ़ाया का अंतिम चलना


140

क्या यह निर्धारित करने का एक तरीका है कि क्या लूप अंतिम बार पुनरावृत्ति कर रहा है। मेरा कोड कुछ इस तरह दिखता है:

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

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

अब बात यह है कि मैं अंतिम यात्रा में अल्पविराम को जोड़ना नहीं चाहता। अब यह निर्धारित करने का एक तरीका है कि क्या यह अंतिम पुनरावृत्ति है या क्या मैं लूप के लिए फंस गया हूं या ट्रैक रखने के लिए बाहरी काउंटर का उपयोग कर रहा हूं।


1
हाँ! यह मजाकिया है, मैं सिर्फ यही सवाल पूछना चाहता था!
फीलो

एक ही तरह का प्रश्न रिटर्न (और ऐसा ही) करेगा। अब आप एक लूप क्यों बनाना चाहेंगे अगर एक तत्व को एक अलग उपचार की आवश्यकता हो? stackoverflow.com/questions/156650/…
xtofl

चूँकि आपके पास एक निश्चित सरणी है, इसलिए संवर्धित का उपयोग क्यों करें? for (int i = 0; मैं <array.length; i ++ अगर (i <array.lenth) ,,,
AnthonyJClink

जवाबों:


223

एक और विकल्प यह है कि आप को जोड़ने से पहले अल्पविराम को जोड़ दें, सिर्फ पहली यात्रा पर नहीं । (कृपया उपयोग न करें "" + i, वैसे - आप वास्तव में यहाँ संगति नहीं चाहते हैं, और StringBuilder एक पूरी तरह से अच्छा परिशिष्ट (int) अधिभार है।)

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

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

इसके बारे में अच्छी बात यह है कि यह किसी भी के साथ काम करेगा Iterable- आप हमेशा चीजों को अनुक्रमित नहीं कर सकते। ("कॉमा जोड़ें और फिर इसे अंत में हटा दें" एक अच्छा सुझाव है जब आप वास्तव में StringBuilder का उपयोग कर रहे हैं - लेकिन यह स्ट्रीम लिखने जैसी चीजों के लिए काम नहीं करता है। यह संभवतः इस सटीक समस्या के लिए सबसे अच्छा तरीका है। )


2
अच्छा पैटर्न, लेकिन बिल्डर .length ()! = 0 भंगुर है - कल्पना करें कि आपके लूप से पहले बफर में कुछ (जोड़ा हुआ) हो जाता है। इसके बजाय, isFirstबूलियन ध्वज का उपयोग करें । बोनस: तेजी से भी।
जेसन कोहेन

2
@ जेसन: मैं निश्चित रूप से "फ़र्स्ट" पैटर्न का उपयोग करता हूं जहां बिल्डर पहले पुनरावृत्ति पर खाली नहीं होगा। हालांकि, जब इसकी आवश्यकता नहीं होती है, तो यह मेरे अनुभव में कार्यान्वयन के लिए उचित मात्रा में ब्लोट जोड़ता है।
जॉन स्कीट

3
@Liverpool (आदि): 1000 अनावश्यक चेकों बहुत, है बहुत प्रदर्शन पर कोई खास असर पड़ने की संभावना नहीं है। मैं समान रूप से इंगित कर सकता हूं कि दीना के समाधान द्वारा अतिरिक्त चरित्र के कारण स्ट्रिंगब्यूलर का विस्तार हो सकता है, अंतिम स्ट्रिंग के आकार को दोगुना करना होगा (कंट)
जॉन स्कीट

2
अनावश्यक बफर स्थान। हालांकि, महत्वपूर्ण बिंदु पठनीयता है। मैं अपने संस्करण को दीना की तुलना में अधिक पठनीय लगता हूं। यदि आप विपरीत तरीके से महसूस करते हैं, तो यह ठीक है। मैं केवल अड़चन खोजने के बाद अनावश्यक "ifs" के प्रदर्शन प्रभाव पर विचार करूंगा।
जॉन स्कीट

3
इसके अलावा, मेरा समाधान एक अधिक सामान्यतः लागू होता है, क्योंकि यह केवल लिखने में सक्षम होने पर निर्भर करता है। आप मेरा समाधान ले सकते हैं और इसे एक धारा आदि में लिखने के लिए बदल सकते हैं - जहां आप बाद में अनावश्यक डेटा को वापस लेने में सक्षम नहीं हो सकते हैं। मुझे ऐसे पैटर्न पसंद हैं जो आमतौर पर लागू होते हैं।
जॉन स्कीट

145

ऐसा करने का एक और तरीका:

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

अपडेट: जावा 8 के लिए, अब आपके पास कलेक्टर हैं


1
मेरे समान उत्तर को हटाना था - जो मुझे सिखाएगा कि अन्य उत्तरों पर अधिक ध्यान से देखने से पहले पोस्ट न करें।
माइकल बूर

1
यह भी ध्यान दें कि यह एक अन्य टिप्पणी थ्रेड में उल्लिखित रॉबर्ट पॉलसन के संभावित मुद्दे को संभालता है - यह तकनीक स्ट्रिंग वैल्यू के खाली होने पर निर्भर नहीं करती है जब सरणी मान जोड़ दिए जाते हैं।
माइकल बूर

1
हालाँकि यह कोड अधिक स्लीक / साफ-सुथरा / मज़ेदार है, लेकिन यह इफ़ेक्ट संस्करण की तुलना में कम स्पष्ट है। हमेशा अधिक स्पष्ट / पठनीय संस्करण का उपयोग करें।
बिल के

8
@ बिल: यह एक कठिन और तेज़ नियम के रूप में महान नहीं है; कई बार 'चतुर' समाधान "अधिक सही" समाधान होता है। इस बिंदु पर अधिक, क्या आप वास्तव में यह संस्करण पढ़ना मुश्किल है? किसी भी तरह से एक अनुचर को इसके माध्यम से कदम रखने की आवश्यकता होगी - मुझे नहीं लगता कि अंतर महत्वपूर्ण है।
ग्रेग केस

यह काम करता है, हालांकि आप फाइलसिस्टम के राइट कॉल जैसे अन्य संसाधन को लिखते हैं। अच्छा विचार।
टक्समैन

39

यह हमेशा आसान हो सकता है। और फिर, जब आप अपने पाश के साथ कर रहे हैं, तो बस अंतिम चरित्र को हटा दें। इस तरह से भी कम सशर्त टन।

आप उपयोग कर सकते हैं StringBuilder'एस deleteCharAt(int index)सूचकांक किया जा रहा है साथlength() - 1


5
इस समस्या के लिए सबसे कुशल समाधान। +1।
रियल रेड।

9
शायद यह मैं हूं, लेकिन मैं वास्तव में इस तथ्य को पसंद नहीं करता हूं कि आप अपने द्वारा जोड़े गए कुछ को हटा रहे हैं ...
Fortega

2
Fortega: मैं हर बार किसी चीज़ की जाँच करना पसंद नहीं करता, जो मैं 99% बार करूँगा। दीना के या सलबुंडी के समाधान को लागू करने के लिए यह अधिक तर्कसंगत लगता है (और यह तेजी से आईएस है)।
भैंस

1
मेरी राय में सबसे सुरुचिपूर्ण समाधान। धन्यवाद!
चार्ल्स मोरिन

32

हो सकता है कि आप जॉब के लिए गलत टूल का इस्तेमाल कर रहे हों।

यह जो आप कर रहे हैं उससे अधिक मैनुअल है, लेकिन यह एक तरह से अधिक सुरुचिपूर्ण है यदि थोड़ा सा "पुराने स्कूल" नहीं है

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

15

यह लगभग StackOverflow प्रश्न का दोहराव है । क्या आप चाहते हैं StringUtils है , और शामिल होने की विधि को कॉल करने के लिए

StringUtils.join(strArr, ',');

14

एक और समाधान (शायद सबसे कुशल)

    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]);
        }
    }

यह एक प्राकृतिक समाधान है सिवाय इसके कि यह सरणी पर निर्भर करता है कि खाली नहीं है।
orcmid

5
@orcmid: यदि सरणी खाली है, तो यह अभी भी सही आउटपुट देता है - एक खाली स्ट्रिंग। मुझे यकीन नहीं है कि आपकी बात क्या है।
एडी


6

स्पष्ट लूप हमेशा अंतर्निहित लोगों की तुलना में बेहतर काम करते हैं।

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

यदि आप शून्य-लंबाई वाले सरणी के साथ काम कर रहे हैं तो आपको पूरी बात को एक if-statement में लपेटना चाहिए।


मुझे यह दृष्टिकोण पसंद है क्योंकि यह प्रत्येक पुनरावृत्ति का परीक्षण करने की आवश्यकता नहीं है। केवल एक चीज जो मैं जोड़ूंगा वह यह है कि बिल्डर सीधे पूर्णांक को जोड़ सकता है इसलिए "+ int" का उपयोग करने की कोई आवश्यकता नहीं है, बस संलग्न करें (सरणी [0])।
जोश

अगर आपको कम से कम एक तत्व है यह सुनिश्चित करने के लिए आपको पूरे लॉट के आसपास एक और की आवश्यकता है।
टॉम ले ने

2
क्यों हर कोई एपेंड के स्ट्रिंग संयोजन के साथ उदाहरणों का उपयोग करता रहता है? "," + x नए स्ट्रिंगबर्ल (",") .append (x) .toString () में संकलित करता है ...
जॉन गार्डनर

@ जोश और @ जॉन: सिर्फ n00b उदाहरण के बाद। एक ही बार में बहुत सी चीजों को पेश नहीं करना चाहते हैं। हालाँकि आपकी बात बहुत अच्छी है।
S.Lott

@ टोम: सही है। मुझे लगता है कि मैंने पहले ही कहा था। कोई संपादन आवश्यक नहीं है।
S.Lott

4

यदि आप इसे क्लासिक इंडेक्स लूप में परिवर्तित करते हैं, तो हाँ।

या आप इसे पूरा करने के बाद अंतिम अल्पविराम को हटा सकते हैं। इस तरह:

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);

मुझे, मैं सिर्फ कॉमन्स-लैंगStringUtils.join() से उपयोग करता हूं ।


3

आपको क्लास सेपरेटर की जरूरत है ।

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

वर्ग Separatorका कार्यान्वयन सीधे आगे है। यह एक स्ट्रिंग को लपेटता है toString()जो पहली कॉल को छोड़कर हर कॉल पर दी जाती है , जो एक खाली स्ट्रिंग लौटाती है।


3

Java.util.AbstractCollection.toString () के आधार पर, यह सीमांकक से बचने के लिए जल्दी बाहर निकलता है।

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

यह कुशल और सुरुचिपूर्ण है, लेकिन कुछ अन्य उत्तरों के रूप में स्वयं स्पष्ट नहीं है।


जब आप प्रारंभिक (! i.hasNext())दृष्टिकोण को शामिल करना भूल गए , जो समग्र दृष्टिकोण की मजबूती का एक महत्वपूर्ण हिस्सा है। (यहां अन्य समाधान खाली संग्रह को इनायत से संभालते हैं, इसलिए आपका भी होना चाहिए! :)
माइक क्लार्क

3

यहाँ एक समाधान है:

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;
}

पहली यात्रा के लिए देखो :)  


3

जैसा कि टूलकिट ने उल्लेख किया है, जावा 8 में अब हमारे पास कलेक्टर हैं । यहाँ कोड क्या दिखेगा:

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

मुझे लगता है कि वह वही करता है जो आप खोज रहे हैं, और यह एक ऐसा पैटर्न है जिसे आप कई अन्य चीजों के लिए उपयोग कर सकते हैं।


1

फिर भी एक और विकल्प।

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

मैंने दूसरे प्रश्न पर एक बदलाव किया
13

1

यहां वर्णित समाधानों में से कई शीर्ष, आईएमएचओ पर थोड़ा सा हैं, खासकर वे जो बाहरी पुस्तकालयों पर भरोसा करते हैं। अल्पविराम से अलग की गई सूची को प्राप्त करने के लिए एक अच्छा साफ, स्पष्ट मुहावरा है जिसका मैंने हमेशा उपयोग किया है। यह सशर्त (?) ऑपरेटर पर निर्भर करता है:

संपादित करें : मूल समाधान सही है, लेकिन टिप्पणियों के अनुसार गैर-इष्टतम है। दूसरी बार कोशिश कर रहा है:

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

वहाँ आप कोड की 4 पंक्तियों में जाते हैं, जिसमें ऐरे और StringBuilder की घोषणा शामिल है।


लेकिन आप प्रत्येक पुनरावृत्ति (+ ऑपरेटर के लिए धन्यवाद) पर एक नया स्ट्रिंगबुल बना रहे हैं।
माइकल मायर्स

हां, यदि आप बाईटकोड में देखते हैं, तो आप सही हैं। मैं विश्वास नहीं कर सकता कि इतना आसान प्रश्न इतना जटिल हो सकता है। मुझे आश्चर्य है कि अगर कंपाइलर यहां अनुकूलन कर सकता है।
जुलिएन चांगसांग

बशर्ते कि दूसरा, बेहतर समाधान की उम्मीद है।
जुलिएन चास्टांग

1

इन परिणामों के साथ यहां एक SSCCE बेंचमार्क चला गया (संबंधित जिसे मुझे लागू करना था):

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

कम से कम मेरे उदाहरण पर, हर यात्रा पर चेक लंघन काफ़ी तेजी से विशेष रूप से डेटा का समझदार मात्रा के लिए नहीं है, लेकिन यह है तेजी से।

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
कृपया अपने स्वयं के बेंचमार्क को रोल न करें और OpenJDKs के अपने स्वयं के माइक्रो बेंचमार्किंग हार्नेस (जेएमएच) का उपयोग करें । यह आपके कोड को गर्म करेगा और सबसे समस्याग्रस्त नुकसान से बचाएगा।
रेने

0

एक अन्य दृष्टिकोण सरणी की लंबाई (यदि उपलब्ध है) एक अलग चर में संग्रहीत है (लंबाई हर बार फिर से जाँचने की तुलना में अधिक कुशल)। आप अंतिम कॉमा जोड़ने के लिए यह निर्धारित करने के लिए अपने इंडेक्स की तुलना उस लंबाई से कर सकते हैं कि नहीं।

संपादित करें: प्रत्येक पुनरावृत्ति में एक सशर्त जाँच होने के खिलाफ एक और विचार अंतिम चरित्र को हटाने की प्रदर्शन लागत (जो एक स्ट्रिंग प्रति हो सकती है) का वजन कर रहा है।


एक अंतिम चरित्र को हटाने के लिए एक स्ट्रिंग प्रतिलिपि नहीं बनानी चाहिए। StringBuffer के डिलीट / DeleteCharAt तरीके अंततः सिस्टम क्लास समरूप स्रोत और गंतव्य सरणियों के अंदर निम्न विधि को कॉल करते हैं: सिस्टम -> सार्वजनिक स्थैतिक देशी शून्य arraycopy (ऑब्जेक्ट src, int srcPos, ऑब्जेक्ट डेस्ट, इंट डेस्टोस, इंट लंबाई);
बफेलो

0

यदि आप किसी सरणी को केवल अल्पविराम सीमांकित सरणी में बदल रहे हैं, तो कई भाषाओं में इसके लिए एक फ़ंक्शन शामिल होता है। यह प्रत्येक तत्व के बीच एक सीमांकक के साथ एक सरणी को एक स्ट्रिंग में बदल देता है।


0

इस मामले में वास्तव में यह जानने की कोई आवश्यकता नहीं है कि क्या यह अंतिम पुनरावृत्ति है। ऐसे कई तरीके हैं जिनसे हम इसे हल कर सकते हैं। एक तरीका होगा:

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

0

यहां दो वैकल्पिक रास्ते हैं:

1: अपाचे कॉमन्स स्ट्रिंग बर्तन

2: बुलियन रखें जिसे firstसही कहा जाए। प्रत्येक पुनरावृत्ति में, यदि firstगलत है , तो अपना अल्पविराम जोड़ें; उसके बाद, firstगलत पर सेट करें।


1) लिंक 2 मर चुका है) मुझे कोड के बजाय विवरण पढ़ने में अधिक समय लग गया :)
भैंस

0

इसकी एक निश्चित सरणी के बाद से, एन्हांस किए गए से बचने के लिए बस आसान होगा ... यदि ऑब्जेक्ट एक संग्रह है तो एक इट्रेटर आसान होगा।

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(",");
   }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.