एक संग्रह / सरणी / सूची से अल्पविराम से अलग स्ट्रिंग्स बनाने का सबसे परिष्कृत तरीका?


98

डेटाबेस के साथ अपने काम के दौरान मैंने देखा कि मैं क्वेरी स्ट्रिंग लिखता हूं और इस तार में मुझे एक सूची / सरणी / संग्रह से जहां-जहां खंड में कई प्रतिबंध लगाने हैं। इस तरह दिखना चाहिए:

select * from customer 
where customer.id in (34, 26, ..., 2);

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

मेरा दृष्टिकोण जो मैंने अब तक इस्तेमाल किया है वह कुछ इस तरह है:

String result = "";
boolean first = true;
for(String string : collectionOfStrings) {
    if(first) {
        result+=string;
        first=false;
    } else {
        result+=","+string;
    }
}

लेकिन यह ऐसा है जैसे आप बहुत बदसूरत देख सकते हैं। आप देख नहीं सकते हैं कि पहली नज़र में क्या होता है, खासकर जब निर्माण किए गए तार (प्रत्येक SQL क्वेरी की तरह) जटिल हो रहे हों।

आपका (अधिक) सुरुचिपूर्ण तरीका क्या है?


संभवतः ऊपर दिखाए गए एसक्यूएल को वास्तव में इस तरह दिखना चाहिए: ग्राहक से * का चयन करें जहां ग्राहक। में (34, 26, 2);
डोनल

एक मुश्किल हिस्सा है, जब सूची आइटम (स्ट्रिंग्स) में खुद कॉमा या डबल-कोट्स होते हैं और उन्हें उद्धरण के साथ भाग जाने की आवश्यकता होती है। अगर मुझे कुछ भी याद नहीं है, तो ऊपर दिए गए उदाहरण इस पर विचार नहीं करते हैं और मुझे सभी ग्रंथों के माध्यम से लूप करने और कॉमा की खोज करने के विचार से नफरत है .. क्या आप इसे हल करने का एक बेहतर तरीका है?
समुराई लड़की

इस उत्तर की जाँच करें ... stackoverflow.com/a/15815631/728610
अरविंद श्रीधरन

क्या आपने कभी stackoverflow.com/questions/10850753/… की जाँच की है ?
हिरेन पटेल

यह करना चाहिए। stackoverflow.com/a/15815631/3157062
पराग जाधव

जवाबों:


85

नोट: यह उत्तर तब अच्छा था जब इसे 11 साल पहले लिखा गया था, लेकिन अब केवल एक जावा लाइन में निर्मित कक्षाओं का उपयोग करके या एक उपयोगिता पुस्तकालय का उपयोग करके, दोनों को एक ही पंक्ति में इसे और अधिक सफाई से करने के लिए बेहतर विकल्प हैं। अन्य उत्तर नीचे देखें।


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

StringBuilder वर्ग को एक उत्परिवर्तनीय स्ट्रिंग ऑब्जेक्ट के रूप में देखा जा सकता है जो अपनी सामग्री को बदलने पर अधिक मेमोरी आवंटित करता है।

बेमानी अनुगामी अल्पविराम का ध्यान रखते हुए प्रश्न में मूल सुझाव और भी अधिक स्पष्ट और कुशलतापूर्वक लिखा जा सकता है :

    StringBuilder result = new StringBuilder();
    for(String string : collectionOfStrings) {
        result.append(string);
        result.append(",");
    }
    return result.length() > 0 ? result.substring(0, result.length() - 1): "";

7
ध्यान दें कि इसके लिए आपके संग्रह में कम से कम एक तत्व होना आवश्यक है।
ग्यूस

3
शीर्ष मतदान उत्तर देखें - code.google.com/p/guava-lbooks/wiki/StringsExplained
gimel

खाली सूची के लिए सुझाए गए फिक्स देखें।
जिमेल

1
अमरूद का जवाब बेहतर है। पहिया को सुदृढ़ करने की कोई आवश्यकता नहीं है।
डेविजजेलसन

1
@ xtreme-biker एक आधुनिक आधुनिक संकलक के साथ, StringBuilder का स्वचालित रूप से उपयोग किया जा सकता है। + = का उपयोग करने से पहले अपने पर्यावरण की जाँच करें। देखें stackoverflow.com/questions/1532461/…
gimel

89

का प्रयोग करें गूगल अमरूद एपीआई की joinविधि:

Joiner.on(",").join(collectionOfStrings);

4
आजकल वर्ग को कहा जाता है Joiner; google-collections.googlecode.com/svn/trunk/javadoc/com/google/…
Jonik

2
और आज, संग्रह हटा दिया गया है। इसके बजाय Google अमरूद का उपयोग करें ।
डायरियो

12
इस बीच, org.apache.commons.lang.StringUtils अपरिवर्तित रहता है। :-)
ओगरे Psalm33

1
अमरूद चला गया है। देख github.com/google/guava/wiki/StringsExplained
gimel

76

मैंने सिर्फ उस कोड को देखा जो आज किया है। यह AviewAnew के उत्तर पर एक भिन्नता है।

collectionOfStrings = /* source string collection */;
String csList = StringUtils.join(collectionOfStrings.toArray(), ",");

StringUtils (<- commons.lang 2.x, या commons.lang 3.x लिंक ) हम इस्तेमाल किया से है अपाचे कॉमन्स


... और StringUtils कहाँ से आती है?
vwegert

1
आह, अच्छी बात है। कुछ समय बाद से मैंने उस कोड को देखा, लेकिन मेरा मानना ​​है कि हम org.apache.commons.lang.StringUsils का उपयोग कर रहे थे।
ओगरे Psalm33


2
अच्छा धन्यवाद। StringUtils # Join भी एक Iterable पर काम करती है, इसलिए संभवतः आपके संग्रह को पहले किसी सरणी में बदलने की कोई आवश्यकता नहीं है।
रॉय

47

जिस तरह से मैं लिखता हूं कि लूप है:

StringBuilder buff = new StringBuilder();
String sep = "";
for (String str : strs) {
    buff.append(sep);
    buff.append(str);
    sep = ",";
}
return buff.toString();

Sep के प्रदर्शन के बारे में चिंता मत करो। एक असाइनमेंट बहुत तेज है। हॉटस्पॉट वैसे भी एक लूप के पहले पुनरावृत्ति को छीलने के लिए जाता है (जैसा कि अक्सर इसे अशक्त और मोनो / बिमॉर्फिक इनलाइनिंग चेक जैसी विषमताओं से निपटना पड़ता है)।

यदि आप इसे बहुत (एक से अधिक बार) का उपयोग करते हैं, तो इसे एक साझा पद्धति में डालें।

स्टैकओवरफ़्लो पर एक और सवाल है कि एक एसक्यूएल स्टेटमेंट में आईडी की सूची कैसे डालें।


42

जावा 8 के बाद से, आप उपयोग कर सकते हैं:


3
यह अच्छा है! यदि आप उन वस्तुओं में हेरफेर कर रहे हैं, जिन्हें एक विशेष स्ट्रिंग रूपांतरण की आवश्यकता नहीं है जिसे objectsString () द्वारा कवर किया गया है, तो ऑब्जेक्ट :: toString को एक java.util.function.Function के साथ बदल दें <YourType, String> जो आपकी कक्षा को एक स्ट्रिंग में मैप करता है।
तोरबेन

2
इसके अलावा, आप इसे इस तरह से उपयोग कर सकते हैं: cats.stream().map(cat -> cat.getName()).collect(Collectors.joining(","));अपने संग्रह से एक एकल चर के लिए।
अंक

मुझे उस प्रदर्शन के बारे में आश्चर्य है stream। Int [] या लंबे [] या अन्य सरणियों के लिए जहां मूल्य को बस डाला जा सकता है String, मैं एक गैर-स्ट्रीमिंग समाधान ढूंढूंगा। वास्तव में मैं देख रहा हूँ।
एडम

11

मैंने इट्रेटर मुहावरे को सुरुचिपूर्ण पाया, क्योंकि इसमें अधिक तत्वों के लिए एक परीक्षण है (संक्षिप्तता के लिए ommited null / खाली परीक्षण):

public static String convert(List<String> list) {
    String res = "";
    for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
        res += iterator.next() + (iterator.hasNext() ? "," : "");
    }
    return res;
}

... और शायद इतना कम कुशल कि स्वीकृत समाधान, 'hasNext ()' कॉल कितना जटिल है, इस पर निर्भर करता है। इसके अलावा, आपको संभवतः स्ट्रिंग संघनन के बजाय स्ट्रिंग स्ट्रिंग का उपयोग करना चाहिए।
स्टीफन सी

ठीक है, यदि आप दक्षता के बारे में picky बनना चाहते हैं, तो एक स्ट्रिंगराइटर का उपयोग करें;)
मिगुएल पिंग

8

इसके लिए बहुत सारे मैनुअल समाधान हैं, लेकिन मैं जूली के उत्तर को फिर से दोहराना और अपडेट करना चाहता था। Google संग्रह योजक वर्ग का उपयोग करें ।

Joiner.on(", ").join(34, 26, ..., 2)

यह var args, iterables और arrays को संभालता है और ठीक से एक char (विभाजक के उत्तर के विपरीत) के विभाजकों को संभालता है। यदि आपको इसकी आवश्यकता है तो यह आपकी सूची में अशक्त मूल्यों को भी संभाल लेगा।


7

यहाँ एक अविश्वसनीय रूप से सामान्य संस्करण है जिसे मैंने पिछले सुझावों के संयोजन से बनाया है:

public static <T> String buildCommaSeparatedString(Collection<T> values) {
    if (values==null || values.isEmpty()) return "";
    StringBuilder result = new StringBuilder();
    for (T val : values) {
        result.append(val);
        result.append(",");
    }
    return result.substring(0, result.length() - 1);
}

7
String.join(", ", collectionOfStrings)

Java8 एपीआई में उपलब्ध है।

(एक गूगल अमरुद निर्भरता जोड़ने की आवश्यकता के बिना) विकल्प:

Joiner.on(",").join(collectionOfStrings);

5

तुम कोशिश कर सकते हो

List collections = Arrays.asList(34, 26, "...", 2);
String asString = collection.toString();
// justValues = "34, 26, ..., 2"
String justValues = asString.substring(1, asString.length()-1);

4

अमरूद या अपाचे कॉमन्स को छोड़कर यह अब तक का सबसे छोटा समाधान होगा

String res = "";
for (String i : values) {
    res += res.isEmpty() ? i : ","+i;
}

0,1 और n तत्व सूची के साथ अच्छा है। लेकिन आपको अशक्त सूची की जांच करनी होगी। मैं GWT में इसका उपयोग करता हूं, इसलिए मैं StringBuilder के बिना अच्छा हूं। और तत्वों के कुछ जोड़े के साथ छोटी सूची के लिए इसके ठीक कहीं और;)


4

यदि किसी ने हाल के दिनों में इस पर ठोकर खाई है, तो मैंने जावा 8 का उपयोग करके एक साधारण बदलाव जोड़ा है reduce()। इसमें कुछ अन्य लोगों द्वारा पहले से वर्णित समाधान भी शामिल हैं:

import java.util.Arrays;
import java.util.List;

import org.apache.commons.lang.StringUtils;    

import com.google.common.base.Joiner;

public class Dummy {
  public static void main(String[] args) {

    List<String> strings = Arrays.asList("abc", "de", "fg");
    String commaSeparated = strings
        .stream()
        .reduce((s1, s2) -> {return s1 + "," + s2; })
        .get();

    System.out.println(commaSeparated);

    System.out.println(Joiner.on(',').join(strings));

    System.out.println(StringUtils.join(strings, ","));

  }
}

4

Android में आपको इसका उपयोग करना चाहिए:

TextUtils.join(",",collectionOfStrings.toArray());

4

मुझे लगता है कि यह एक अच्छा विचार नहीं है जहां आप कर रहे हैं जहां खंड मानों को समाप्‍त करें।

SELECT.... FROM.... WHERE ID IN( value1, value2,....valueN)

जहां valueXस्ट्रिंग्स की सूची से आता है।

सबसे पहले, यदि आप स्ट्रिंग्स की तुलना कर रहे हैं तो उन्हें उद्धृत किया जाना चाहिए, यह स्ट्रिंग्स के अंदर एक उद्धरण हो सकता है तो यह तुच्छ नहीं है।

दूसरा, यदि मान उपयोगकर्ता या अन्य सिस्टम से आता है, तो SQL इंजेक्शन हमला संभव है।

यह बहुत अधिक क्रिया है लेकिन आपको जो करना चाहिए वह इस तरह से एक स्ट्रिंग बनाना है:

SELECT.... FROM.... WHERE ID IN( ?, ?,....?)

और फिर चर को बांधें Statement.setString(nParameter,parameterValue)


3

इस समस्या से निपटने के लिए बस एक और तरीका। सबसे छोटा नहीं है, लेकिन यह कुशल है और काम पूरा कर लेता है।

/**
 * Creates a comma-separated list of values from given collection.
 * 
 * @param <T> Value type.
 * @param values Value collection.
 * @return Comma-separated String of values.
 */
public <T> String toParameterList(Collection<T> values) {
   if (values == null || values.isEmpty()) {
      return ""; // Depending on how you want to deal with this case...
   }
   StringBuilder result = new StringBuilder();
   Iterator<T> i = values.iterator();
   result.append(i.next().toString());
   while (i.hasNext()) {
      result.append(",").append(i.next().toString());
   }
   return result.toString();
}

2

कुछ तृतीय-पक्ष जावा पुस्तकालय हैं जो स्ट्रिंग में शामिल होने की विधि प्रदान करते हैं, लेकिन आप शायद इस तरह से कुछ सरल के लिए पुस्तकालय का उपयोग शुरू नहीं करना चाहते हैं। मैं बस इस तरह से एक सहायक विधि बनाऊंगा, जो मुझे लगता है कि आपके संस्करण की तुलना में थोड़ा बेहतर है, यह StringBuffer का उपयोग करता है, जो आपको कई तार से जुड़ने की आवश्यकता होने पर अधिक कुशल होगा, और यह किसी भी प्रकार के संग्रह पर काम करता है।

public static <T> String join(Collection<T> values)
{
    StringBuffer ret = new StringBuffer();
    for (T value : values)
    {
        if (ret.length() > 0) ret.append(",");
        ret.append(value);
    }
    return ret.toString();
}

Collection.toString () का उपयोग करने के साथ एक और सुझाव कम है, लेकिन यह Collection.toString () पर निर्भर करता है जो बहुत विशिष्ट प्रारूप में एक स्ट्रिंग लौटाता है, जिसे मैं व्यक्तिगत रूप से भरोसा नहीं करना चाहता हूं।


2

यदि आप स्प्रिंग का उपयोग करते हैं, तो आप कर सकते हैं:

StringUtils.arrayToCommaDelimitedString(
    collectionOfStrings.toArray()
)

(पैकेज org.springframework.util)


1

मुझे यकीन नहीं है कि यह "परिष्कृत" कैसे है, लेकिन यह निश्चित रूप से थोड़ा छोटा है। यह विभिन्न प्रकार के संग्रह जैसे कि सेट <Integer>, List <String>, आदि के साथ काम करेगा।

public static final String toSqlList(Collection<?> values) {

    String collectionString = values.toString();

    // Convert the square brackets produced by Collection.toString() to round brackets used by SQL
    return "(" + collectionString.substring(1, collectionString.length() - 1) + ")";
}

पाठक के लिए व्यायाम : इस विधि को संशोधित करें ताकि यह सही ढंग से एक शून्य / खाली संग्रह को संभाल सके :)


1

क्या कोड बदसूरत बनाता है पहले मामले के लिए विशेष-हैंडलिंग है। इस छोटे स्निपेट में अधिकांश लाइनें समर्पित हैं, कोड की नियमित नौकरी करने के लिए नहीं, बल्कि उस विशेष मामले को संभालने के लिए। और यही विकल्प है कि लूप के बाहर विशेष हैंडलिंग को आगे बढ़ाते हुए गिमेल के समाधान जैसे विकल्प। एक विशेष मामला है (ठीक है, आप शुरू और अंत दोनों को विशेष मामलों के रूप में देख सकते हैं - लेकिन उनमें से केवल एक को विशेष रूप से इलाज करने की आवश्यकता है), इसलिए इसे लूप के अंदर संभालना अनावश्यक रूप से जटिल है।


1

मैंने अभी-अभी अपने लाइब्रेरी डॉलर के लिए एक परीक्षण में जाँच की है :

@Test
public void join() {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    String string = $(list).join(",");
}

इसके चारों ओर सूचियों / सरणियों / तार / आदि एक धाराप्रवाह आवरण का उपयोग कर बनाने के लिए केवल एक ही स्थिर आयात : $

एनबी :

पिछली सूची का उपयोग कर के रूप में फिर से लिखा जा सकता है $(1, 5).join(",")


1

IN अभिव्यक्ति के बारे में अच्छी बात यह है कि यदि आपके पास बार-बार मान हैं, तो यह परिणाम नहीं बदलता है। तो, बस पहले आइटम को डुप्लिकेट करें और पूरी सूची को संसाधित करें। यह मानता है कि सूची में कम से कम एक आइटम है। यदि कोई आइटम नहीं हैं, तो मैं उस पहले के लिए जाँच करूँगा और फिर SQL को निष्पादित नहीं करने का सुझाव दूंगा।

यह चाल चलेगा, स्पष्ट है कि यह क्या कर रहा है और किसी भी बाहरी पुस्तकालय पर निर्भर नहीं है:

StringBuffer inString = new StringBuffer(listOfIDs.get(0).toString());
for (Long currentID : listOfIDs) {
  inString.append(",").append(currentID);
}

1

जबकि मुझे लगता है कि आपका सबसे अच्छा दांव गुवा से योजक का उपयोग करना है, अगर मुझे इसे हाथ से कोड करना था तो मुझे यह दृष्टिकोण अधिक सुरुचिपूर्ण लगता है कि 'पहला' झंडा या अंतिम अल्पविराम को काट देना।

private String commas(Iterable<String> strings) {
    StringBuilder buffer = new StringBuilder();
    Iterator<String> it = strings.iterator();
    if (it.hasNext()) {
        buffer.append(it.next());
        while (it.hasNext()) {
            buffer.append(',');
            buffer.append(it.next());
        }
    }

    return buffer.toString();
}


1

एक और विकल्प, जो मैं यहां देख रहा हूं (मामूली संशोधनों के साथ) के आधार पर।

public static String toString(int[] numbers) {
    StringBuilder res = new StringBuilder();
    for (int number : numbers) {
        if (res.length() != 0) {
            res.append(',');
        }
        res.append(number);
    }
    return res.toString();
}

1

ज्वाइन 'मेथड्स' एरे और एसे वर्गों में उपलब्ध हैं जो विस्तार करते हैं AbstractCollectionsलेकिन toString()विधि को ओवरराइड नहीं करते हैं (जैसे लगभग सभी संग्रह java.util)।

उदाहरण के लिए:

String s= java.util.Arrays.toString(collectionOfStrings.toArray());
s = s.substing(1, s.length()-1);// [] are guaranteed to be there

यह काफी अजीब तरीका है क्योंकि यह केवल एक जैसे डेटा SQL वार के लिए काम करता है।


1
List<String> collectionOfStrings = // List of string to concat
String csvStrings = StringUtils.collectionToDelimitedString(collectionOfStrings, ",");

स्प्रिंगफ्रेमोव्रक से स्ट्रिंगिल्टिल्स: स्प्रिंग-कोर



0
java.util.List<String> lista = new java.util.ArrayList<String>();
lista.add("Hola");
lista.add("Julio");
System.out.println(lista.toString().replace('[','(').replace(']',')'));

$~(Hola, Julio)

1
यह एक बुरा अभ्यास है। आप यह धारणा नहीं बना सकते हैं कि कार्यान्वयन कार्यान्वयन में परिवर्तन होता है।
अक्टूबर 19'15

0
String commaSeparatedNames = namesList.toString().replaceAll( "[\\[|\\]| ]", "" );  // replace [ or ] or blank

स्ट्रिंग प्रतिनिधित्व में संग्रह के तत्वों की एक सूची होती है, जिस क्रम में वे इसके पुनरावर्तक द्वारा लौटाए जाते हैं, जो चौकोर कोष्ठकों में संलग्न होते हैं ("[]")। आसन्न तत्वों को वर्णों द्वारा अलग किया जाता है "," (अल्पविराम और स्थान)।

एब्सट्रैक्टलेक्शन जेवाडॉक


0

सूची टोकन = नया एरियरलिस्ट (परिणाम); अंतिम StringBuilder बिल्डर = नया StringBuilder ();

    for (int i =0; i < tokens.size(); i++){
        builder.append(tokens.get(i));
        if(i != tokens.size()-1){
            builder.append(TOKEN_DELIMITER);
        }
    }

builder.toString ();

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.