एक वेक्टर <int> को एक स्ट्रिंग में बदलें


92

मेरे पास एक vector<int>कंटेनर है जिसमें पूर्णांक हैं (जैसे {1,2,3,4}) और मैं प्रपत्र की एक स्ट्रिंग में परिवर्तित करना चाहूंगा

"1,2,3,4"

C ++ में ऐसा करने का सबसे साफ तरीका क्या है? पायथन में यह है कि मैं यह कैसे करूंगा:

>>> array = [1,2,3,4]
>>> ",".join(map(str,array))
'1,2,3,4'

1
निकटता से संबंधित: stackoverflow.com/questions/4850473/…
Ciro Santilli 郝海东 stack stack stack 病

जवाबों:


95

निश्चित रूप से पायथन के रूप में सुरुचिपूर्ण नहीं है, लेकिन सी ++ में पायथन के रूप में कुछ भी उतना ही सुरुचिपूर्ण नहीं है।

आप एक का उपयोग कर सकते हैं stringstream...

#include <sstream>
//...

std::stringstream ss;
for(size_t i = 0; i < v.size(); ++i)
{
  if(i != 0)
    ss << ",";
  ss << v[i];
}
std::string s = ss.str();

आप std::for_eachइसके बदले उपयोग भी कर सकते हैं ।


मुझे लगता है कि आप array.size () नहीं v.size (), नहीं?
मार्क इलियट

1
फिर जो भी वेक्टर कहा जाता है।
ब्रायन आर। बॉडी

2
वह होना चाहिए std::string s = ss.str()। यदि आप एक का const char*उपयोग करना चाहते हैं s.c_str()। (ध्यान दें, जबकि वाक्यात्मक रूप से सही होने पर, ss.str().c_str()आप एक const char*अस्थायी को एक अंक देंगे जो पूर्ण अभिव्यक्ति के अंत में मौजूद नहीं रहेगा। यह दर्द होता है।)
sbi

1
क्यों न केवल string.append का उपयोग करें?
बैयंग हुआंग

12
जवाब बिना अधूरा है#include <sstream>
renadeen

43

Std :: for_each और lambda का उपयोग करके आप कुछ रोचक कर सकते हैं।

#include <iostream>
#include <sstream>

int main()
{
     int  array[] = {1,2,3,4};
     std::for_each(std::begin(array), std::end(array),
                   [&std::cout, sep=' '](int x) mutable {
                       out << sep << x; sep=',';
                   });
}

मैंने जो थोड़ी सी कक्षा लिखी, उसके लिए यह प्रश्न देखें । यह अनुगामी अल्पविराम मुद्रित नहीं करेगा। इसके अलावा अगर हम मानते हैं कि C ++ 14 हमें इस तरह के एल्गोरिदम के रेंज आधारित समकक्ष देना जारी रखेगा:

namespace std {
   // I am assuming something like this in the C++14 standard
   // I have no idea if this is correct but it should be trivial to write if it  does not appear.
   template<typename C, typename I>
   void copy(C const& container, I outputIter) {copy(begin(container), end(container), outputIter);}
}
using POI = PrefexOutputIterator;   
int main()
{
     int  array[] = {1,2,3,4};
     std::copy(array, POI(std::cout, ","));
  // ",".join(map(str,array))               // closer
}

12
मुझे लगता है कि यह पायथन के जुड़ने के बराबर नहीं है - यह अंत में एक अतिरिक्त "," सम्मिलित करेगा।
1800 सूचना

2
समतुल्य नहीं, लेकिन केवल सुरुचिपूर्ण के रूप में (वास्तव में मैं ऐसा अधिक सोचता हूं लेकिन यह सिर्फ एक राय है)।
मार्टिन

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

1
आप स्ट्रिंग :: मूल सदस्य फ़ंक्शन का उपयोग करके अंतिम कॉमा को अनदेखा कर सकते हैं। आपके परिणाम चर में 0 से n-1 तक सबस्ट्रिंग असाइन करें।
Dan

@SteveJessop: बेहतर है?
मार्टिन यॉर्क

24

आप एसटीडी :: जमा का उपयोग कर सकते हैं। निम्नलिखित उदाहरण पर विचार करें

if (v.empty() 
    return std::string();
std::string s = std::accumulate(v.begin()+1, v.end(), std::to_string(v[0]),
                     [](const std::string& a, int b){
                           return a + ',' + std::to_string(b);
                     });

','होना चाहिए","
मैट

2
@ मैट ऑपरेटर के stringलिए एक अधिभार है +जो वर्णों को भी स्वीकार कर सकता है। तो ','ठीक है।
पवन मंजूनाथ

19

एक अन्य विकल्प का उपयोग std::copyऔर ostream_iteratorवर्ग है:

#include <iterator>  // ostream_iterator
#include <sstream>   // ostringstream
#include <algorithm> // copy

std::ostringstream stream;
std::copy(array.begin(), array.end(), std::ostream_iterator<>(stream));
std::string s=stream.str();
s.erase(s.length()-1);

पायथन के रूप में भी अच्छा नहीं है। इस उद्देश्य के लिए, मैंने एक joinसमारोह बनाया :

template <class T, class A>
T join(const A &begin, const A &end, const T &t)
{
  T result;
  for (A it=begin;
       it!=end;
       it++)
  {
    if (!result.empty())
      result.append(t);
    result.append(*it);
  }
  return result;
}

फिर इसे इस तरह इस्तेमाल किया:

std::string s=join(array.begin(), array.end(), std::string(","));

आप पूछ सकते हैं कि मैं पुनरावृत्तियों में क्यों पारित हुआ। खैर, वास्तव में मैं सरणी को उलटना चाहता था, इसलिए मैंने इसे इस तरह से इस्तेमाल किया:

std::string s=join(array.rbegin(), array.rend(), std::string(","));

आदर्श रूप में, मैं उस बिंदु पर टेम्पलेट देना चाहूंगा जहां यह चार प्रकार का अनुमान लगा सकता है, और स्ट्रिंग-स्ट्रीम का उपयोग कर सकता है, लेकिन मैं अभी तक इसका पता नहीं लगा सका।


चूंकि यह एक टिप्पणी के लिए बहुत अधिक होगा, इसलिए मैंने एक उत्तर ( stackoverflow.com/questions/1430757/1432040#1432040 ) पोस्ट किया है जो आपके अंतिम वाक्य में दी गई पहेली को हल करने का प्रयास करता है।
sbi

आपके joinफ़ंक्शन का उपयोग वैक्टर के साथ भी किया जा सकता है? आप कृपया उदाहरण दें, मैं C ++ में नया हूं।
Noitidart

क्या आप उत्तर में पुनरावृत्ति के लिए पुनरावृत्ति को बदल सकते हैं?
मिल्ली स्मिथ

14

बूस्ट और सी ++ 11 के साथ इस तरह हासिल किया जा सकता है:

auto array = {1,2,3,4};
join(array | transformed(tostr), ",");

हां तकरीबन। यहां देखें पूरा उदाहरण:

#include <array>
#include <iostream>

#include <boost/algorithm/string/join.hpp>
#include <boost/range/adaptor/transformed.hpp>

int main() {
    using boost::algorithm::join;
    using boost::adaptors::transformed;
    auto tostr = static_cast<std::string(*)(int)>(std::to_string);

    auto array = {1,2,3,4};
    std::cout << join(array | transformed(tostr), ",") << std::endl;

    return 0;
}

प्रेटोरियन को श्रेय ।

आप इस तरह से किसी भी मूल्य प्रकार को संभाल सकते हैं:

template<class Container>
std::string join(Container const & container, std::string delimiter) {
  using boost::algorithm::join;
  using boost::adaptors::transformed;
  using value_type = typename Container::value_type;

  auto tostr = static_cast<std::string(*)(value_type)>(std::to_string);
  return join(container | transformed(tostr), delimiter);
};

11

यह सिर्फ 1800 सूचना द्वारा दी गई पहेली को हल करने का एक प्रयास है जिसमें उसके दूसरे समाधान की उदारता की कमी है, सवाल का जवाब देने का प्रयास नहीं:

template <class Str, class It>
Str join(It begin, const It end, const Str &sep)
{
  typedef typename Str::value_type     char_type;
  typedef typename Str::traits_type    traits_type;
  typedef typename Str::allocator_type allocator_type;
  typedef std::basic_ostringstream<char_type,traits_type,allocator_type>
                                       ostringstream_type;
  ostringstream_type result;

  if(begin!=end)
    result << *begin++;
  while(begin!=end) {
    result << sep;
    result << *begin++;
  }
  return result.str();
}

मेरी मशीन (टीएम) पर काम करता है।


Visual Studio 2013 बहुत ही उलझन में है typedefs द्वारा। ऐसा नहीं है कि आप यह जान सकते हैं कि 2009 में।
Grault

@Jes: मैं अब इसे 5mins के लिए घूर रहा हूं, लेकिन यह पता नहीं लगा सका कि VS क्या यात्रा कर सकता है। क्या आप अधिक विशिष्ट हो सकते हैं?
sbi

मुझे क्षमा करें, मुझे लगता है कि मैंने बिना << अतिभार के वस्तुओं के शामिल होने का प्रयास किया था, जो अब मुझे एहसास हुआ कि आपके कोड के लिए अनुचित है। मैं आपके कोड को स्ट्रिंग के वेक्टर से संकलित नहीं कर सकता। एक साइड नोट पर, वीएस 2013 समुदाय "एक्सप्रेस" संस्करणों के विपरीत स्वतंत्र और सुविधा-पूर्ण दोनों है।
गूलर

@Jes: यह किसी भी प्रकार के साथ काम करना चाहिए जिसे स्ट्रीम किया जा सकता है (यानी, operator<<अतिभारित है)। बेशक, एक प्रकार के बिना operator<<बहुत भ्रामक त्रुटि संदेश हो सकता है।
sbi

दुर्भाग्य से, यह संकलन नहीं करता है join(v.begin(), v.end(), ","):। यदि sepतर्क एक स्ट्रिंग शाब्दिक है तो टेम्पलेट तर्क कटौती सही परिणाम नहीं देती है। इस मुद्दे के समाधान के लिए मेरा प्रयास । इसके अलावा अधिक आधुनिक रेंज-आधारित अधिभार प्रदान करना।
zett42 19

7

टेम्पलेट / विचारों के बहुत सारे। मेरा सामान्य या कुशल के रूप में नहीं है, लेकिन मैं सिर्फ एक ही समस्या थी और इस मिश्रण में कुछ कम और मीठा के रूप में फेंकना चाहता था। यह लाइनों की सबसे कम संख्या पर जीतता है ... :)

std::stringstream joinedValues;
for (auto value: array)
{
    joinedValues << value << ",";
}
//Strip off the trailing comma
std::string result = joinedValues.str().substr(0,joinedValues.str().size()-1);

1
सरलीकृत कोड के लिए धन्यवाद। अतिरिक्त प्रतियों से बचने और कुछ आसान प्रदर्शन लाभ प्राप्त करने के लिए इसे "ऑटो और" में बदलना चाह सकते हैं।
मिल्ली स्मिथ

substr(...)उपयोग pop_back()करने के बजाय , अंतिम चरित्र को हटाने के लिए उपयोग करें, तब और अधिक स्पष्ट और साफ हो जाता है।
ifyalciner

4

यदि आप करना चाहते हैं std::cout << join(myVector, ",") << std::endl;, तो आप कुछ ऐसा कर सकते हैं:

template <typename C, typename T> class MyJoiner
{
    C &c;
    T &s;
    MyJoiner(C &&container, T&& sep) : c(std::forward<C>(container)), s(std::forward<T>(sep)) {}
public:
    template<typename C, typename T> friend std::ostream& operator<<(std::ostream &o, MyJoiner<C, T> const &mj);
    template<typename C, typename T> friend MyJoiner<C, T> join(C &&container, T&& sep);
};

template<typename C, typename T> std::ostream& operator<<(std::ostream &o, MyJoiner<C, T> const &mj)
{
    auto i = mj.c.begin();
    if (i != mj.c.end())
    {
        o << *i++;
        while (i != mj.c.end())
        {
            o << mj.s << *i++;
        }
    }

    return o;
}

template<typename C, typename T> MyJoiner<C, T> join(C &&container, T&& sep)
{
    return MyJoiner<C, T>(std::forward<C>(container), std::forward<T>(sep));
}

ध्यान दें, यह समाधान द्वितीयक बफ़र बनाने के बजाय सीधे आउटपुट स्ट्रीम में शामिल होता है और किसी भी प्रकार के साथ काम करेगा जो एक ऑपरेटर है <a ostream।

यह भी काम करता है जहां boost::algorithm::join()विफल रहता है, तो आप एक है जब vector<char*>एक के बजाय vector<string>


4
string s;
for (auto i : v)
    s += (s.empty() ? "" : ",") + to_string(i);

7
ढेर अतिप्रवाह में आपका स्वागत है! हालांकि यह कोड समस्या को हल कर सकता है, लेकिन विस्तार को जोड़ना और यह समझाना सबसे अच्छा है कि यह उन लोगों के लिए कैसे काम करता है जो इस कोड के टुकड़े को नहीं समझ सकते हैं।
पेपर ११११

1
वर्तमान शीर्ष उत्तर अधिक विस्तृत नहीं है, और यह सबसे छोटा / साफ काम करने वाला उत्तर है। std::stringstreamबड़े सरणियों के लिए उतना कुशल नहीं है क्योंकि यह उत्तर के लिए stringstreamआकार की एक सरणी के लिए O (n²) के बजाय O (n.log (n)) प्रदर्शन के लिए अग्रणी, आशावादी रूप से स्मृति आवंटित करने में सक्षम होगा n। इसके अलावा के stringstreamलिए अस्थायी तार का निर्माण नहीं हो सकता है to_string(i)
अबेरूद

2

मुझे 1800 का जवाब पसंद है। हालाँकि मैं पहले पुनरावृति को लूप से बाहर ले जाऊंगा क्योंकि यदि परिणाम केवल पहले पुनरावृत्ति के बाद एक बार बदलता है

template <class T, class A>
T join(const A &begin, const A &end, const T &t)
{
  T result;
  A it = begin;
  if (it != end) 
  {
   result.append(*it);
   ++it;
  }

  for( ;
       it!=end;
       ++it)
  {
    result.append(t);
    result.append(*it);
  }
  return result;
}

यदि आप चाहें तो इसे कम बयानों तक सीमित किया जा सकता है:

template <class T, class A>
T join(const A &begin, const A &end, const T &t)
{
  T result;
  A it = begin;
  if (it != end) 
   result.append(*it++);

  for( ; it!=end; ++it)
   result.append(t).append(*it);
  return result;
}

आपको अज्ञात पुनरावृत्त प्रकारों के लिए पोस्ट-इंक्रीमेंट का उपयोग नहीं करना चाहिए। वह महंगा हो सकता है। (बेशक, जब तार के साथ काम करते हैं, तो इससे बहुत फर्क नहीं पड़ सकता है। लेकिन एक बार जब आप आदत सीख लेते हैं ...)
sbi

जब तक आप लौटे हुए टेंपरेरी वैल्यू का उपयोग करते हैं, तब तक पोस्ट इंक्रीमेंट ठीक है। उदाहरण के लिए "result.append (* it); ++ it?" लगभग हमेशा उतना ही महंगा होता है जितना कि "result.append (* it ++);" दूसरे में पुनरावृत्त की एक अतिरिक्त प्रति है।

उफ़ मैं अभी लूप के लिए पोस्ट इंक्रीमेंट स्पॉट किया। कॉपी और पेस्ट त्रुटि। मैंने पद तय कर लिया है।
इयान

1
@ इयान: जब मैंने सी ++ पढ़ाया, तो मैंने अपने छात्रों को यह बताने के लिए इस्तेमाल किया ++iकि उन्हें वास्तव में जहां जरूरत थी, सिवाय इसके कि वे i++इसे भूल जाने पर ही इसे भूल नहीं जाते। (मेरे साथ भी ऐसा ही था, बीटीडब्ल्यू।) उन्होंने पहले जावा सीख लिया था, जहां सभी तरह के सी-आइएमएस प्रचलित हैं और इसमें उन्हें कुछ महीने लग गए (प्रति सप्ताह 1 व्याख्यान + प्रयोगशाला काम), लेकिन अंत में अधिकांश उन्होंने पूर्व वेतन वृद्धि का उपयोग करने की आदत सीखी।
sbi

1
@ एसबीआई: सहमत हूं मैं हमेशा पूर्वनिर्धारण के लिए भी डिफ़ॉल्ट हूं, बदमाश पोस्टपिनरमेंट किसी लूप के लिए किसी और को कॉपी करने और इसे बदलने से आया है। मेरे पहले उत्तर में मुझे लगा कि आप "result.append (* it ++)" के बारे में चिंतित थे और लूप के लिए नहीं। लूप में पोस्ट इंक्रीमेंट देखकर मैं थोड़ा शर्मिंदा हुआ। कुछ लोग पोस्ट इन्क्रीमेंट का उपयोग बहुत दूर न करने की सलाह का पालन करते हुए लगते हैं और कभी भी इसका उपयोग नहीं करते हैं या उचित होने पर इसे बदल भी देते हैं। हालाँकि मुझे पता है कि अब आप इस श्रेणी में नहीं आते हैं।
इयान

2

समस्या का सुरुचिपूर्ण समाधान प्रदान करने के कुछ दिलचस्प प्रयास हैं। ओपी की मूल दुविधा का प्रभावी ढंग से जवाब देने के लिए मुझे टेम्प्लेटेड धाराओं का उपयोग करने का विचार था। हालांकि यह एक पुरानी पोस्ट है, मैं भविष्य के उपयोगकर्ताओं को उम्मीद कर रहा हूं जो इस पर ठोकर खाते हैं, जो मेरे समाधान को लाभप्रद पाएंगे।

सबसे पहले, कुछ उत्तर (स्वीकृत उत्तर सहित) पुन: प्रयोज्य को बढ़ावा नहीं देते हैं। चूंकि सी ++ मानक पुस्तकालय में तार जुड़ने के लिए एक सुरुचिपूर्ण तरीका प्रदान नहीं करता है (जो मैंने देखा है), यह एक ऐसा बनाना महत्वपूर्ण है जो लचीला और पुन: प्रयोज्य है। यहाँ पर मेरा शॉट है:

// Replace with your namespace //
namespace my {
    // Templated join which can be used on any combination of streams, iterators and base types //
    template <typename TStream, typename TIter, typename TSeperator>
    TStream& join(TStream& stream, TIter begin, TIter end, TSeperator seperator) {
        // A flag which, when true, has next iteration prepend our seperator to the stream //
        bool sep = false;                       
        // Begin iterating through our list //
        for (TIter i = begin; i != end; ++i) {
            // If we need to prepend a seperator, do it //
            if (sep) stream << seperator;
            // Stream the next value held by our iterator //
            stream << *i;
            // Flag that next loops needs a seperator //
            sep = true;
        }
        // As a convenience, we return a reference to the passed stream //
        return stream;
    }
}

अब इसका उपयोग करने के लिए, आप बस निम्नलिखित की तरह कुछ कर सकते हैं:

// Load some data //
std::vector<int> params;
params.push_back(1);
params.push_back(2);
params.push_back(3);
params.push_back(4);

// Store and print our results to standard out //
std::stringstream param_stream;
std::cout << my::join(param_stream, params.begin(), params.end(), ",").str() << std::endl;

// A quick and dirty way to print directly to standard out //
my::join(std::cout, params.begin(), params.end(), ",") << std::endl;

ध्यान दें कि कैसे धाराओं का उपयोग इस समाधान को अविश्वसनीय रूप से लचीला बनाता है क्योंकि हम अपने परिणाम को बाद में पुनः प्राप्त करने के लिए एक स्ट्रिंगस्ट्रीम में संग्रहीत कर सकते हैं, या हम सीधे मानक आउट, एक फ़ाइल, या यहां तक ​​कि एक धारा के रूप में लागू नेटवर्क कनेक्शन के लिए लिख सकते हैं। मुद्रित किया जा रहा प्रकार केवल स्रोत स्ट्रीम के साथ चलने योग्य और संगत होना चाहिए। एसटीएल विभिन्न धाराओं को प्रदान करता है जो कई प्रकार की बड़ी रेंज के साथ संगत होती हैं। इसलिए आप वास्तव में इसके साथ शहर जा सकते हैं। मेरे सिर के ऊपर से, आपका वेक्टर int, फ्लोट, डबल, स्ट्रिंग, अहस्ताक्षरित int, SomeObject *, और बहुत कुछ हो सकता है।


1

मैंने एक विस्तारित शामिल समर्थन जोड़ने के लिए एक सहायक हेडर फ़ाइल बनाई है।

बस अपनी सामान्य हेडर फ़ाइल के नीचे दिए गए कोड को जोड़ें और जब जरूरत हो तब इसे शामिल करें।

उपयोग के उदाहरण:

/* An example for a mapping function. */
ostream&
map_numbers(ostream& os, const void* payload, generic_primitive data)
{
    static string names[] = {"Zero", "One", "Two", "Three", "Four"};
    os << names[data.as_int];
    const string* post = reinterpret_cast<const string*>(payload);
    if (post) {
        os << " " << *post;
    }
    return os;
}

int main() {
    int arr[] = {0,1,2,3,4};
    vector<int> vec(arr, arr + 5);
    cout << vec << endl; /* Outputs: '0 1 2 3 4' */
    cout << join(vec.begin(), vec.end()) << endl; /* Outputs: '0 1 2 3 4' */
    cout << join(vec.begin(), vec.begin() + 2) << endl; /* Outputs: '0 1 2' */
    cout << join(vec.begin(), vec.end(), ", ") << endl; /* Outputs: '0, 1, 2, 3, 4' */
    cout << join(vec.begin(), vec.end(), ", ", map_numbers) << endl; /* Outputs: 'Zero, One, Two, Three, Four' */
    string post = "Mississippi";
    cout << join(vec.begin() + 1, vec.end(), ", ", map_numbers, &post) << endl; /* Outputs: 'One Mississippi, Two mississippi, Three mississippi, Four mississippi' */
    return 0;
}

दृश्य के पीछे कोड:

#include <iostream>
#include <vector>
#include <list>
#include <set>
#include <unordered_set>
using namespace std;

#define GENERIC_PRIMITIVE_CLASS_BUILDER(T) generic_primitive(const T& v) { value.as_##T = v; }
#define GENERIC_PRIMITIVE_TYPE_BUILDER(T) T as_##T;

typedef void* ptr;

/** A union that could contain a primitive or void*,
 *    used for generic function pointers.
 * TODO: add more primitive types as needed.
 */
struct generic_primitive {
    GENERIC_PRIMITIVE_CLASS_BUILDER(int);
    GENERIC_PRIMITIVE_CLASS_BUILDER(ptr);
    union {
        GENERIC_PRIMITIVE_TYPE_BUILDER(int);
        GENERIC_PRIMITIVE_TYPE_BUILDER(ptr);
    };
};

typedef ostream& (*mapping_funct_t)(ostream&, const void*, generic_primitive);
template<typename T>
class Join {
public:
    Join(const T& begin, const T& end,
            const string& separator = " ",
            mapping_funct_t mapping = 0,
            const void* payload = 0):
            m_begin(begin),
            m_end(end),
            m_separator(separator),
            m_mapping(mapping),
            m_payload(payload) {}

    ostream&
    apply(ostream& os) const
    {
        T begin = m_begin;
        T end = m_end;
        if (begin != end)
            if (m_mapping) {
                m_mapping(os, m_payload, *begin++);
            } else {
                os << *begin++;
            }
        while (begin != end) {
            os << m_separator;
            if (m_mapping) {
                m_mapping(os, m_payload, *begin++);
            } else {
                os << *begin++;
            }
        }
        return os;
    }
private:
    const T& m_begin;
    const T& m_end;
    const string m_separator;
    const mapping_funct_t m_mapping;
    const void* m_payload;
};

template <typename T>
Join<T>
join(const T& begin, const T& end,
     const string& separator = " ",
     ostream& (*mapping)(ostream&, const void*, generic_primitive) = 0,
     const void* payload = 0)
{
    return Join<T>(begin, end, separator, mapping, payload);
}

template<typename T>
ostream&
operator<<(ostream& os, const vector<T>& vec) {
    return join(vec.begin(), vec.end()).apply(os);
}

template<typename T>
ostream&
operator<<(ostream& os, const list<T>& lst) {
    return join(lst.begin(), lst.end()).apply(os);
}

template<typename T>
ostream&
operator<<(ostream& os, const set<T>& s) {
    return join(s.begin(), s.end()).apply(os);
}

template<typename T>
ostream&
operator<<(ostream& os, const Join<T>& vec) {
    return vec.apply(os);
}

1

यहाँ एक सामान्य C ++ 11 समाधान है जो आपको करने देगा

int main() {
    vector<int> v {1,2,3};
    cout << join(v, ", ") << endl;
    string s = join(v, '+').str();
}

कोड है:

template<typename Iterable, typename Sep>
class Joiner {
    const Iterable& i_;
    const Sep& s_;
public:
    Joiner(const Iterable& i, const Sep& s) : i_(i), s_(s) {}
    std::string str() const {std::stringstream ss; ss << *this; return ss.str();}
    template<typename I, typename S> friend std::ostream& operator<< (std::ostream& os, const Joiner<I,S>& j);
};

template<typename I, typename S>
std::ostream& operator<< (std::ostream& os, const Joiner<I,S>& j) {
    auto elem = j.i_.begin();
    if (elem != j.i_.end()) {
        os << *elem;
        ++elem;
        while (elem != j.i_.end()) {
            os << j.s_ << *elem;
            ++elem;
        }
    }
    return os;
}

template<typename I, typename S>
inline Joiner<I,S> join(const I& i, const S& s) {return Joiner<I,S>(i, s);}

1

निम्नलिखित तत्वों को एक में बदलने के लिए एक सरल और व्यावहारिक तरीका vectorहै string:

std::string join(const std::vector<int>& numbers, const std::string& delimiter = ",") {
    std::ostringstream result;
    for (const auto number : numbers) {
        if (result.tellp() > 0) { // not first round
            result << delimiter;
        }
        result << number;
    }
    return result.str();
}

आप की जरूरत #include <sstream>के लिए ostringstream


1

एक सामान्य समाधान पर @sbi के प्रयास पर विस्तार करना जो std::vector<int>एक विशिष्ट रिटर्न स्ट्रिंग प्रकार या तक सीमित नहीं है । नीचे प्रस्तुत कोड का उपयोग इस तरह किया जा सकता है:

std::vector<int> vec{ 1, 2, 3 };

// Call modern range-based overload.
auto str     = join( vec,  "," );
auto wideStr = join( vec, L"," );

// Call old-school iterator-based overload.
auto str     = join( vec.begin(), vec.end(),  "," );
auto wideStr = join( vec.begin(), vec.end(), L"," );

मूल कोड में, टेम्पलेट तर्क कटौती सही रिटर्न स्ट्रिंग प्रकार का उत्पादन करने के लिए काम नहीं करता है यदि विभाजक एक स्ट्रिंग शाब्दिक है (जैसा कि ऊपर के नमूनों में है)। इस स्थिति Str::value_typeमें, फ़ंक्शन बॉडी में टाइप किए गए प्रकार गलत हैं। कोड मानता है कि Strहमेशा एक प्रकार है std::basic_string, इसलिए यह स्पष्ट रूप से स्ट्रिंग शाब्दिकों के लिए विफल रहता है।

इसे ठीक करने के लिए, निम्न कोड विभाजक तर्क से केवल वर्ण प्रकार को कम करने की कोशिश करता है और डिफ़ॉल्ट रिटर्न स्ट्रिंग प्रकार का उत्पादन करने के लिए इसका उपयोग करता है। यह प्रयोग करके हासिल किया जाता है boost::range_value, जो दिए गए श्रेणी प्रकार से तत्व प्रकार को निकालता है ।

#include <string>
#include <sstream>
#include <boost/range.hpp>

template< class Sep, class Str = std::basic_string< typename boost::range_value< Sep >::type >, class InputIt >
Str join( InputIt first, const InputIt last, const Sep& sep )
{
    using char_type          = typename Str::value_type;
    using traits_type        = typename Str::traits_type;
    using allocator_type     = typename Str::allocator_type;
    using ostringstream_type = std::basic_ostringstream< char_type, traits_type, allocator_type >;

    ostringstream_type result;

    if( first != last )
    {
        result << *first++;
    }
    while( first != last ) 
    {
        result << sep << *first++;
    }
    return result.str();
}

अब हम आसानी से एक रेंज-आधारित अधिभार प्रदान कर सकते हैं, जो कि इट्रेटर-आधारित अधिभार के लिए बस आगे:

template <class Sep, class Str = std::basic_string< typename boost::range_value<Sep>::type >, class InputRange>
Str join( const InputRange &input, const Sep &sep )
{
    // Include the standard begin() and end() in the overload set for ADL. This makes the 
    // function work for standard types (including arrays), aswell as any custom types 
    // that have begin() and end() member functions or overloads of the standalone functions.
    using std::begin; using std::end;

    // Call iterator-based overload.
    return join( begin(input), end(input), sep );
}

कोलिरु में लाइव डेमो


0

जैसा कि @capone ने किया था,

std::string join(const std::vector<std::string> &str_list , 
                 const std::string &delim=" ")
{
    if(str_list.size() == 0) return "" ;
    return std::accumulate( str_list.cbegin() + 1, 
                            str_list.cend(), 
                            str_list.at(0) , 
                            [&delim](const std::string &a , const std::string &b)
                            { 
                                return a + delim + b ;
                            }  ) ; 
}

template <typename ST , typename TT>
std::vector<TT> map(TT (*op)(ST) , const vector<ST> &ori_vec)
{
    vector<TT> rst ;
    std::transform(ori_vec.cbegin() ,
                  ori_vec.cend() , back_inserter(rst) , 
                  [&op](const ST& val){ return op(val)  ;} ) ;
    return rst ;
}

तो हम निम्नलिखित की तरह कॉल कर सकते हैं:

int main(int argc , char *argv[])
{
    vector<int> int_vec = {1,2,3,4} ;
    vector<string> str_vec = map<int,string>(to_string, int_vec) ;
    cout << join(str_vec) << endl ;
    return 0 ;
}

अजगर की तरह:

>>> " ".join( map(str, [1,2,3,4]) )

0

मैं कुछ इस तरह का उपयोग करता हूं

namespace std
{

// for strings join
string to_string( string value )
{
    return value;
}

} // namespace std

namespace // anonymous
{

template< typename T >
std::string join( const std::vector<T>& values, char delimiter )
{
    std::string result;
    for( typename std::vector<T>::size_type idx = 0; idx < values.size(); ++idx )
    {
        if( idx != 0 )
            result += delimiter;
        result += std::to_string( values[idx] );
    }
    return result;
}

} // namespace anonymous

0

मैंने @ sbi के उत्तर के साथ शुरुआत की, लेकिन अधिकांश समय एक परिणामी स्ट्रिंग को एक धारा में पाइपिंग करने के लिए समाप्त कर दिया ताकि नीचे का घोल बनाया जाए जो कि मेमोरी में पूर्ण स्ट्रिंग बनाने के ओवरहेड के बिना एक स्ट्रीम में पाइप किया जा सके।

इसका उपयोग इस प्रकार किया जाता है:

#include "string_join.h"
#include <iostream>
#include <vector>

int main()
{
  std::vector<int> v = { 1, 2, 3, 4 };
  // String version
  std::string str = join(v, std::string(", "));
  std::cout << str << std::endl;
  // Directly piped to stream version
  std::cout << join(v, std::string(", ")) << std::endl;
}

जहां string_join.h है:

#pragma once

#include <iterator>
#include <sstream>

template<typename Str, typename It>
class joined_strings
{
  private:
    const It begin, end;
    Str sep;

  public:
    typedef typename Str::value_type char_type;
    typedef typename Str::traits_type traits_type;
    typedef typename Str::allocator_type allocator_type;

  private:
    typedef std::basic_ostringstream<char_type, traits_type, allocator_type>
      ostringstream_type;

  public:
    joined_strings(It begin, const It end, const Str &sep)
      : begin(begin), end(end), sep(sep)
    {
    }

    operator Str() const
    {
      ostringstream_type result;
      result << *this;
      return result.str();
    }

    template<typename ostream_type>
    friend ostream_type& operator<<(
      ostream_type &ostr, const joined_strings<Str, It> &joined)
    {
      It it = joined.begin;
      if(it!=joined.end)
        ostr << *it;
      for(++it; it!=joined.end; ++it)
        ostr << joined.sep << *it;
      return ostr;
    }
};

template<typename Str, typename It>
inline joined_strings<Str, It> join(It begin, const It end, const Str &sep)
{
  return joined_strings<Str, It>(begin, end, sep);
}

template<typename Str, typename Container>
inline joined_strings<Str, typename Container::const_iterator> join(
  Container container, const Str &sep)
{
  return join(container.cbegin(), container.cend(), sep);
}

0

मैंने निम्नलिखित कोड लिखा है। यह C # string.join में आधारित है। यह std :: string और std :: wstring और कई प्रकार के वैक्टर के साथ काम करता है। (टिप्पणियों में उदाहरण)

इसे इस तरह से कॉल करें:

 std::vector<int> vVectorOfIds = {1, 2, 3, 4, 5};

 std::wstring wstrStringForSQLIn = Join(vVectorOfIds, L',');

कोड:

// Generic Join template (mimics string.Join() from C#)
// Written by RandomGuy (stackoverflow) 09-01-2017
// Based on Brian R. Bondy anwser here:
// http://stackoverflow.com/questions/1430757/c-vector-to-string
// Works with char, wchar_t, std::string and std::wstring delimiters
// Also works with a different types of vectors like ints, floats, longs
template<typename T, typename D>
auto Join(const std::vector<T> &vToMerge, const D &delimiter)
{
    // We use std::conditional to get the correct type for the stringstream (char or wchar_t)
    // stringstream = basic_stringstream<char>, wstringstream = basic_stringstream<wchar_t>
    using strType =
        std::conditional<
        std::is_same<D, std::string>::value,
        char,
            std::conditional<
            std::is_same<D, char>::value,
            char,
            wchar_t
            >::type
        >::type;

    std::basic_stringstream<strType> ss;

    for (size_t i = 0; i < vToMerge.size(); ++i)
    {
        if (i != 0)
            ss << delimiter;
        ss << vToMerge[i];
    }
    return ss.str();
}

0

यहाँ पूर्णांक के वेक्टर को तार में बदलने का एक आसान तरीका है।

#include <bits/stdc++.h>
using namespace std;
int main()
{
    vector<int> A = {1, 2, 3, 4};
    string s = "";
    for (int i = 0; i < A.size(); i++)
    {
        s = s + to_string(A[i]) + ",";
    }
    s = s.substr(0, s.length() - 1); //Remove last character
    cout << s;
}

0

टेम्पलेट फ़ंक्शन का उपयोग करके शामिल हों

मैंने आइटमों में template functionशामिल होने के लिए एक का उपयोग किया vector, और ifकेवल पहले वाले आइटम के माध्यम से पुनरावृत्ति करके अनावश्यक विवरण को हटा दिया vector, फिर forलूप के बाद अंतिम आइटम में शामिल हो गया । यह अतिरिक्त स्ट्रिंग के अंत में अतिरिक्त विभाजक को हटाने के लिए अतिरिक्त कोड की आवश्यकता को भी रोकता है। इसलिए, कोई ifबयान पुनरावृत्ति को धीमा नहीं कर रहा है और कोई भी अलग-थलग विभाजक नहीं है जिसकी जरूरत है।

यह एक में शामिल होने का एक सुंदर समारोह कॉल पैदा करता है vectorकी string, integerया double, आदि

मैंने दो संस्करण लिखे: एक स्ट्रिंग लौटाता है; दूसरा सीधे एक धारा में लिखता है।

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;

// Return a string of joined vector items.
template<typename T>
string join(const vector<T>& v, const string& sep)
{
    ostringstream oss;
    const auto LAST = v.end() - 1;
    // Iterate through the first to penultimate items appending the separator.
    for (typename vector<T>::const_iterator p = v.begin(); p != LAST; ++p)
    {
        oss << *p << sep;
    }
    // Join the last item without a separator.
    oss << *LAST;
    return oss.str();
}

// Write joined vector items directly to a stream.
template<typename T>
void join(const vector<T>& v, const string& sep, ostream& os)
{
    const auto LAST = v.end() - 1;
    // Iterate through the first to penultimate items appending the separator.
    for (typename vector<T>::const_iterator p = v.begin(); p != LAST; ++p)
    {
        os << *p << sep;
    }
    // Join the last item without a separator.
    os << *LAST;
}

int main()
{
    vector<string> strings
    {
        "Joined",
        "from",
        "beginning",
        "to",
        "end"
    };
    vector<int> integers{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    vector<double> doubles{ 1.2, 3.4, 5.6, 7.8, 9.0 };

    cout << join(strings, "... ") << endl << endl;
    cout << join(integers, ", ") << endl << endl;
    cout << join(doubles, "; ") << endl << endl;

    join(strings, "... ", cout);
    cout << endl << endl;
    join(integers, ",  ", cout);
    cout << endl << endl;
    join(doubles, ";  ", cout);
    cout << endl << endl;

    return 0;
}

उत्पादन

Joined... from... beginning... to... end

1, 2, 3, 4, 5, 6, 7, 8, 9, 10

1.2; 3.4; 5.6; 7.8; 9

Joined... from... beginning... to... end

1, 2, 3, 4, 5, 6, 7, 8, 9, 10

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