를 사용하여 STL/부스트를 찾을 수정 일치하는 요소에서 벡터
문제
말하자 나는 벡터는 다음과 같이 선언 this:
struct MYSTRUCT
{
float a;
float b;
};
std::vector<MYSTRUCT> v;
지금,나는 원하는 모든 요소를 찾 v 을 공유하는 동일하고 그들의 평균 b,즉
말 v 포함 이 다섯 가지 요소{a,b}:{1, 1}, {1, 2}, {2, 1}, {1, 3}, {2, 2}
를 얻고 싶 v[0],v[1],v[3](는 1)그리고 평균 b:(1 + 2 + 3)/3 = 2, v[2]v[4](는 2)및 평균 b:(1+2)/2=1.5
나 v 는 다음과 같습니다.{1, 2}, {1, 2}, {2, 1.5}, {1, 2}, {2, 1.5}
나는 정말 잘 알고 STL 또는 강화할 수 있도록 만 작업을 수행하는 방법을 알아내는 이를"검색"방법에서는 C++,하지만 나는 STL(람다 식?) 고 강화(람다?) 라이브러리를 해결할 수 있습이 더 우아하게 표현합니다.
편집 그냥 참고,여기 나의(일)무력 할 수있는 방법:
for(int j = 0; j < tempV.size(); j++)
{
MYSTRUCT v = tempV.at(j);
int matchesFound = 0;
for(int k = 0; k < tempV.size(); k++)
{
if(k != j && v.a == tempV.at(k).a)
{
v.b += tempV.at(k).b;
matchesFound++;
}
}
if(matchesFound > 0)
{
v.b = v.b/matchesFound;
}
finalV.push_back(v);
}
해결책
다만 생각은 소리로 이것을 끝낼 수 있습은 상당히 바보:
struct Average {
Average() : total(0), count(0) {}
operator float() const { return total / count; }
Average &operator+=(float f) {
total += f;
++count;
}
float total;
int count;
};
struct Counter {
Counter (std::map<int, Average> &m) : averages(&m) {}
Counter operator+(const MYSTRUCT &s) {
(*averages)[s.a] += s.b;
return *this;
}
std::map<int, Average> *averages;
};
std::map<int, Average> averages;
std::accumulate(v.begin(), v.end(), Counter(averages));
BOOST_FOREACH(MYSTRUCT &s, v) {
s.b = averages[s.a];
}
Hmm.지 않은 완전히 어리석은,하지만 아마도 하지 매력적인 중...
다른 팁
스케치의 솔루션:
sort(v.begin(), v.end());
vector<MYSTRUCT>::iterator b = v.begin(), e = v.end();
while (b != e) {
vector<MYSTRUCT>::iterator m = find_if(b, e, bind(&MYSTRUCT::a, _1) != b->a);
float x = accumulate(b, m, 0.f, _1 + bind(&MYSTRUCT::b,_2)) / (m-b);
for_each(b, m, bind(&MYSTRUCT::a, _1) = x);
b = m;
}
그것은 좋은 하나 때문에,하지만,그것은 정확히 무엇이었을 요청(덕분에 정렬),그리고 여전히지 않는 정말 기분이 깨끗하다.내 생각에는 어떤 filter_iterators 및 transform_iterators 또는 무언가를 가능성이 줄 수 있는 훨씬 더 많은 기능적인 스타일의 대답이다.
다른 방법이 바로 내가 그 생각하는 시간-복잡한 현명한 점근 동일합니다.
typedef map<float, vector<float>> map_type;
map_type m;
BOOST_FOREACH(MYSTRUCT const &s, v) {
m[s.a].push_back(s.b);
}
BOOST_FOREACH(map_type::reference p, m) {
float x = accumulate(p.second.begin(), p.second.end(), 0.0f) / p.second.size();
p.second.assign(1, x);
}
BOOST_FOREACH(MYSTRUCT &s, v) {
s.b = m[s.a].front();
}
다만,그것은 단지 약간 우아한 방법 코드를 무차별 솔루션은 기능적인 스타일의 방법입니다.
아마 힘 접근법?...
struct MYAVG
{
int count;
float avg;
};
// first pass - calculate averages
for ( vector < MYSTRUCT >::iterator first = v.begin();
first != v.end(); ++first )
{
MYAVG myAvg;
myAvg.count = 1;
myAvg.avg = first->b;
if ( mapAvg.find( first->a ) == mapAvg.end() )
mapAvg[ first->a ] = myAvg;
else
{
mapAvg[ first->a ].count++;
mapAvg[ first->a ].avg =
( ( mapAvg[ first->a ].avg * ( mapAvg[ first->a ].count - 1 ) )
+ myAvg.avg ) / mapAvg[ first->a ].count;
}
}
// second pass - update average values
for ( vector < MYSTRUCT >::iterator second = v.begin();
second != v.end(); ++second )
second->b = mapAvg[ second->a ].avg;
나이 테스트의 값으로 당신을 공급하고 필요한 벡터-그것은 정확히 최선,하지만 난 그것은 아주 쉽게 따라(수 있습니다 더 바람직한 복잡한 알고리즘).
피 C-는 스타일!그것이 무엇 C++을 위해 설계되었습니다 것입니다.고 싶을 강조한 명확하고 가독성을 높입니다.
#include <algorithm>
#include <iostream>
#include <map>
#include <numeric>
#include <vector>
#include <boost/assign/list_of.hpp>
using namespace std;
using namespace boost::assign;
struct mystruct
{
mystruct(float a, float b)
: a(a), b(b)
{ }
float a;
float b;
};
vector <mystruct> v =
list_of ( mystruct(1, 1) ) (1, 2) (2, 1) (1, 3) (2, 2);
ostream& operator<<(
ostream& out, mystruct const& data)
{
out << "{" << data.a << ", " << data.b << "}";
return out;
}
ostream& operator<<(
ostream& out, vector <mystruct> const& v)
{
copy(v.begin(), v.end(),
ostream_iterator <mystruct> (out, " "));
return out;
}
struct average_b
{
map <float, float> sum;
map <float, int> count;
float operator[] (float a) const
{
return sum.find(a)->second / count.find(a)->second;
}
};
average_b operator+ (
average_b const& average,
mystruct const& s)
{
average_b result( average );
result.sum[s.a] += s.b;
++result.count[s.a];
return result;
}
struct set_b_to_average
{
set_b_to_average(average_b const& average)
: average(average)
{ }
mystruct operator()(mystruct const& s) const
{
return mystruct(s.a, average[s.a]);
}
average_b const& average;
};
int main()
{
cout << "before:" << endl << v << endl << endl;
transform(v.begin(), v.end(),
v.begin(), set_b_to_average(
accumulate(v.begin(), v.end(), average_b())
));
cout << "after:" << endl << v << endl << endl;
}
사용할 수 있습니다""파티션 알고리즘과 함께"축적된다."
예
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
struct test
{
float a;
float b;
test(const float one, const float two)
: a(one), b(two)
{
}
};
struct get_test_a {
float interesting;
get_test_a(const float i)
: interesting(i)
{
}
bool operator()(const test &value) const
{
static const float epi = 1e-6;
return value.a < interesting + epi &&
value.a > interesting - epi;
}
};
struct add_test_b {
float operator()(const float init, const test &value) const
{
return init + value.b;
}
};
int main(int argc, char **argv)
{
using std::partition;
using std::accumulate;
using std::distance;
typedef std::vector<test> container;
container myContainer;
// Say 'myVector' contains these five elements {a, b}:
// {1, 1}, {1, 2}, {2, 1}, {1, 3}, {2, 2}
myContainer.push_back(test(1, 1));
myContainer.push_back(test(1, 2));
myContainer.push_back(test(2, 1));
myContainer.push_back(test(1, 3));
myContainer.push_back(test(2, 2));
// I want to get v[0], v[1], v[3] (where a is 1) and
// average b: (1 + 2 + 3)/3 = 2,
// and v[2] and v[4] (where a is 2) and average b: (1+2)/2 = 1.5
const container::iterator split =
partition(myContainer.begin(), myContainer.end(),
get_test_a(1));
const float avg_of_one =
accumulate(myContainer.begin(), split, 0.0f, add_test_b())
/ distance(myContainer.begin(), split);
const float avg_of_others =
accumulate(split, myContainer.end(), 0.0f, add_test_b())
/ distance(split, myContainer.end());
std::cout << "The 'b' average of test values where a = 1 is "
<< avg_of_one << std::endl;
std::cout << "The 'b' average of the remaining test values is "
<< avg_of_others << std::endl;
return 0;
}
문서에서 gcc 글
/**
* @brief Move elements for which a predicate is true to the beginning
* of a sequence.
* @ingroup mutating_algorithms
* @param first A forward iterator.
* @param last A forward iterator.
* @param pred A predicate functor.
* @return An iterator @p middle such that @p pred(i) is true for each
* iterator @p i in the range @p [first,middle) and false for each @p i
* in the range @p [middle,last).
*
* @p pred must not modify its operand. @p partition() does not preserve
* the relative ordering of elements in each group, use
* @p stable_partition() if this is needed.
*/
template<typename _ForwardIterator, typename _Predicate>
inline _ForwardIterator
partition(_ForwardIterator __first, _ForwardIterator __last,
_Predicate __pred)
/**
* @brief Accumulate values in a range with operation.
*
* Accumulates the values in the range [first,last) using the function
* object @a binary_op. The initial value is @a init. The values are
* processed in order.
*
* @param first Start of range.
* @param last End of range.
* @param init Starting value to add other values to.
* @param binary_op Function object to accumulate with.
* @return The final sum.
*/
template<typename _InputIterator, typename _Tp, typename _BinaryOperation>
inline _Tp
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init,
_BinaryOperation __binary_op)
그것은 보인다는 가장 쉬운 방법은 적당히 복잡한 함수해 colelction:
struct CountAllAverages {
typedef std::pair<float, unsigned> average_t;
std::map<float, average_t> averages;
void operator()(mystruct& ms) {
average_t& average = averages[ms.a];
average.second++;
average.first += ms.b;
}
float getAverage(float a) { return averages[a].first/averages[a].second; }
};
쓰 C++,당신은 균형을 유지하는 간의 재사용성(예:재사용 기존의 알고리즘과 데이터 구조)그리고 가독성을 높입니다.onebyone 가까운이었지만,자신의 솔루션이 더욱 향상될 수 있:
template<class T>
struct average {
T total;
int count;
mutable bool calculated;
mutable T average_value;
average & operator+=(T const & value) {
total += value;
++count;
calculated = false;
}
T value() const {
if(!calculated) {
calculated = true;
average_value = total / count;
}
return average_value;
}
};
std::map< float, average<float> > averages;
BOOST_FOREACH(MYSTRUCT &element, v) {
averages[element.a] += element.b;
}
BOOST_FOREACH(MYSTRUCT &element, v) {
element.b = averages[element.a].value();
}
보너스에 대한 포인트는 재사용할 수 있는"average"유형입니다.
struct MYSTRUCT {
float x;
float y;
operator float() const { return y; }
};
class cmp {
float val;
public:
cmp(float v) : val(v) {}
bool operator()(MYSTRUCT const &a) { return a.x != val; }
};
float masked_mean(std::vector<MYSTRUCT> const &in, MYSTRUCT const &mask) {
std::vector<float> temp;
std::remove_copy_if(in.begin(), in.end(), std::back_inserter(temp), cmp(mask.x));
return std::accumulate(temp.begin(), temp.end(), 0.0f) / temp.size();
}