2010-07-08 7 views
10

मान लें कि मेरे पास निम्न ऑब्जेक्ट है:कंटेनर में सभी तत्वों के लिए सदस्य फ़ंक्शन के परिणाम को योग करने का सबसे अच्छा तरीका क्या है?

struct Foo 
{ 
    int size() { return 2; } 
}; 

vector<Foo> में सभी ऑब्जेक्ट्स का कुल size प्राप्त करने का सबसे अच्छा तरीका (सबसे रखरखाव योग्य, पठनीय, आदि) क्या है? मैं अपना समाधान पोस्ट करूंगा लेकिन मुझे बेहतर विचारों में दिलचस्पी है।

अद्यतन:

अब तक हमारे पास है:

  • std :: संचय और एक मज़ेदार
  • std :: संचय और एक लैम्ब्डा अभिव्यक्ति
  • plain ol for for lop

क्या कोई अन्य व्यावहारिक समाधान है? क्या आप boost::bind या std::bind1st/2nd का उपयोग करके कुछ बनाए रखने योग्य बना सकते हैं?

+3

'std :: वेक्टर vec के लिए सीमा के आधार पर; vec.size() * 2', क्योंकि हम जानते हैं कि 'Foo :: size' हमेशा 2 देता है। :) – jalf

उत्तर

23

अपने खुद के सुझाव के अलावा, अपने संकलक C++ 0x लैम्ब्डा भाव का समर्थन करता है, तो आप इस छोटा संस्करण काम कर सकते हैं:

std::vector<Foo> vf; 

// do something to populate vf 


int totalSize = std::accumulate(vf.begin(), 
           vf.end(), 
           0, 
           [](int sum, const Foo& elem){ return sum + elem.size();}); 
+0

टाइपो: लैम्बडा के शरीर के अंत में एक अर्धविराम गायब है (मैं खुद को संपादित नहीं कर सकता)। – rafak

7

std::accumulate और एक मजेदार का उपयोग करें।

#include <functional> 
#include <numeric> 

struct SumSizes : public std::binary_function<int, Foo, int> 
{ 
    int operator()(int total, const Foo& elem) const 
    { 
     return total + elem.size(); 
    } 
}; 

std::vector<Foo> vf; 

// do something to populate vf 

int totalSize = std::accumulate(vf.begin(), 
           vf.end(), 
           0, 
           SumSizes()); 
+0

आपका समाधान सबसे बेवकूफ है, लेकिन इस तरह के साधारण मामलों में एक गूंगा इटरेटर लूप आसान हो सकता है। – Philipp

+0

+1 जेनेरिकिटी के लिए 'SumSizes' templating द्वारा इसे बेहतर किया जाएगा, क्योंकि सभी मानक कंटेनरों में 'आकार()' सदस्य कार्य होता है। –

+0

@ जोन, मुझे लगता है कि आपने इस सवाल को गलत समझा होगा। बिंदु कंटेनर का आकार नहीं प्राप्त करना था, लेकिन सभी तत्वों के सदस्य फ़ंक्शन के परिणाम को जोड़ना था। शायद 'आकार' इस तरह के एक समारोह के लिए एक गरीब नाम था। –

4

यहाँ नीचे करने वाली पृथ्वी समाधान है:

typedef std::vector<Foo> FooVector; 
FooVector vf; 
int totalSize = 0; 
for (FooVector::const_iterator it = vf.begin(); it != vf.end(); ++it) { 
    totalSize += it->size(); 
} 
+0

अन्य, कार्यात्मक समाधानों की तुलना में पढ़ने के लिए बहुत आसान है। – Jon

7

मुझे बूस्ट इटरेटर्स लालित्य मिलते हैं, हालांकि वे थोड़ा वर्बोज़ हो सकते हैं (श्रेणी-आधारित एल्गोरिदम इसे बेहतर बना देंगे)। इस मामले में transform iterators काम कर सकते हैं:

#include <boost/iterator/transform_iterator.hpp> 
//... 

int totalSize = std::accumulate(
    boost::make_transform_iterator(vf.begin(), std::mem_fn(&Foo::size)), 
    boost::make_transform_iterator(vf.end(), std::mem_fn(&Foo::size)),0); 

संपादित करें: "boost::bind(&Foo::size,_1)" की जगह द्वारा "std::mem_fn(&Foo::size)"

संपादित करें: मैं बस में पाया गया कि Boost.Range पुस्तकालय रेंज एल्गोरिदम लागू करने के लिए अद्यतन किया गया है!

#include <boost/range/distance.hpp> // numeric.hpp needs it (a bug?) 
#include <boost/range/numeric.hpp> // accumulate 
#include <boost/range/adaptor/transformed.hpp> // transformed 
//... 
int totalSize = boost::accumulate(
    vf | boost::adaptors::transformed(std::mem_fn(Foo::size)), 0); 

नोट:: प्रदर्शन लगभग एक ही कर रहे हैं (मेरी टिप्पणी देखें): यहाँ एक ही समाधान का एक नया संस्करण है आंतरिक रूप से, transformedtransorm_iterator उपयोग करता है।

+1

मैंने इस समाधान और प्रत्यक्ष की तुलना में समय किया, और दुर्भाग्य से यह धीमा है (मुझे 2 और 5 के बीच एक कारक मिला)। हालांकि यह चिंता का विषय नहीं हो सकता है। – rafak

+0

मुझे लगता है कि यह सबसे अच्छा जवाब है। समस्या यह है कि ** क्या ** जमा करना है, जिसे कस्टम इटरेटर द्वारा संबोधित किया जाता है, ** ** ** कैसे जमा नहीं किया जाता है, जिसे एक मज़ेदार का उपयोग करके संबोधित किया जाता है। डिफ़ॉल्ट संचय व्यवहार (प्लस) _is_ जो आप चाहते हैं। इस समस्या को आंतरिक उत्पाद में विस्तारित करने पर विचार करें: परिवर्तित इटरेटर पुन: प्रयोज्य है जबकि मज़ेदार नहीं है। प्रत्येक एल्गोरिदम के लिए एक नया मज़ेदार केवल सदस्य आकार() के संदर्भ में डिफ़ॉल्ट व्यवहार को फिर से परिभाषित करने की आवश्यकता होगी। –

4

सी ++ 11 (और आगे) का उपयोग करते हुए पाश

std::vector<Foo> vFoo; 
// populate vFoo with some values... 
int totalSize = 0; 
for (const auto& element: vFoo) { 
    totalSize += element.size(); 
} 
संबंधित मुद्दे

 संबंधित मुद्दे