|
-
July 2nd, 2009, 08:10 AM
#1
math function on individual struct attributes in an array
I have a couple of struct:
Code:
struct MyData_t
{
int dataA;
int dataB;
}
struct MyHistory_t
{
struct MyData_t data;
long time;
}
then I have a vector:
typedef std::vector<MyHistory_t> HistoryList_t;
HistoryList_t history;
I fill my vector with half a dozen values and then I want to perform a median function on just dataA. But other times I may want to perform a median of both dataA and dataB. I can provide some of the code for the math functions, but I think the problem is found in how I structured my data.
What do you guys think about the code I've shown so far? How can I make it more elegant and easier to do math operations on individual data arrays. One idea is to write a function to return an array of dataA and another for dataB. I'll post more info in a bit.
-
July 2nd, 2009, 08:25 AM
#2
Re: math function on individual struct attributes in an array
The key will be defining predicate functors which operate only on the particular field(s) that interest you.
For instance, you could write a comparison functor which defines a less-than relation based only on data1, and then use it with std::nth_element() to find the median in that sense. Then define another functor which compares based on something else and run the algorithm again.
So long as you can get away with comparison functors, you can stick with the standard library. If you want to get into any of the algorithms in <numeric>, though, you'll probably need to break out boost::transform_iterator and write "selection" functors.
-
July 2nd, 2009, 08:32 AM
#3
Re: math function on individual struct attributes in an array
Really, though, this is too abstract.
It would help to understand the relationships here. What concepts are embodied by dataA and dataB, how are they related?
History, I understand the implication there, but when you say "median of both dataA and dataB" is that sum( dataA + dataB ) / volume, or two columns at once?
At least, that's what's needed to respond to your question about the structure of your data.
Last edited by JVene; July 2nd, 2009 at 08:36 AM.
If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).
-
July 2nd, 2009, 09:04 AM
#4
Re: math function on individual struct attributes in an array
 Originally Posted by JVene
Really, though, this is too abstract.
It would help to understand the relationships here. What concepts are embodied by dataA and dataB, how are they related?
History, I understand the implication there, but when you say "median of both dataA and dataB" is that sum( dataA + dataB ) / volume, or two columns at once?
At least, that's what's needed to respond to your question about the structure of your data.
sorry that what I said was a bit confusing. I don't want the median of the the sum of dataA and dataB. The data is not related in that way, it is just data gather at the same point in time from two different sources. I will need the median of dataA array and dataB arrays separately.
-
July 2nd, 2009, 09:11 AM
#5
Re: math function on individual struct attributes in an array
 Originally Posted by Lindley
The key will be defining predicate functors which operate only on the particular field(s) that interest you.
For instance, you could write a comparison functor which defines a less-than relation based only on data1, and then use it with std::nth_element() to find the median in that sense. Then define another functor which compares based on something else and run the algorithm again.
So long as you can get away with comparison functors, you can stick with the standard library. If you want to get into any of the algorithms in <numeric>, though, you'll probably need to break out boost::transform_iterator and write "selection" functors.
I have comparison functions for that. I use them as the third argument for std::sort(). I am not allowed to use boost.
The algorithms works, I just want a more elegant and generic way of doing it. Right now for each data I need both a comparison function and a median function. But in reality, the data types may be the same type (all ints). So if my struct grows to include dataC, dataD, dataE and dataF, I'll need 12 functions. Can I narrow that down to only needing two functions?
This is tough to describe so bear with me.
-
July 2nd, 2009, 09:37 AM
#6
Re: math function on individual struct attributes in an array
 Originally Posted by sdcode
The algorithms works, I just want a more elegant and generic way of doing it. Right now for each data I need both a comparison function and a median function. But in reality, the data types may be the same type (all ints). So if my struct grows to include dataC, dataD, dataE and dataF, I'll need 12 functions. Can I narrow that down to only needing two functions?
I have an idea involving the use of templates and pointers to member variables. It seems to work, but I am not sure if it adequately answers your question. Anyway, here's my example:
Code:
#include <iostream>
#include <algorithm>
struct A
{
int a;
int b;
};
template<typename T, typename MemberType1, typename MemberType2>
class LessThan
{
public:
LessThan(MemberType1 T::*member1, MemberType2 T::*member2)
: member1(member1), member2(member2) {}
bool operator()(const T& lhs, const T& rhs) const
{
return lhs.*member1 < rhs.*member1
|| (lhs.*member1 == rhs.*member1 && lhs.*member2 < rhs.*member2);
}
private:
MemberType1 T::*member1;
MemberType2 T::*member2;
};
int main()
{
A a[] = {{1, 3}, {2, 2}, {1, 1}};
const std::size_t size = sizeof(a) / sizeof(a[0]);
std::sort(a, a + size, LessThan<A, int, int>(&A::a, &A::b));
for (std::size_t i = 0; i < size; ++i)
{
std::cout << a[i].a << ' ' << a[i].b << '\n';
}
}
Last edited by laserlight; July 2nd, 2009 at 09:47 AM.
Reason: Get rid of magic number and changed sample data slightly.
-
July 2nd, 2009, 09:48 AM
#7
Re: math function on individual struct attributes in an array
That'd work, certainly. The only change I'd make is to define a constructor function which returns a LessThan<T,A,B>----since function templates can deduce their own arguments, it would alleviate the need to specify all three template parameters each time the functor was specified.
-
July 2nd, 2009, 10:03 AM
#8
Re: math function on individual struct attributes in an array
 Originally Posted by laserlight
I have an idea involving the use of templates and pointers to member variables. It seems to work, but I am not sure if it adequately answers your question. Anyway, here's my example:
Code:
#include <iostream>
#include <algorithm>
struct A
{
int a;
int b;
};
template<typename T, typename MemberType1, typename MemberType2>
class LessThan
{
public:
LessThan(MemberType1 T::*member1, MemberType2 T::*member2)
: member1(member1), member2(member2) {}
bool operator()(const T& lhs, const T& rhs) const
{
return lhs.*member1 < rhs.*member1
|| (lhs.*member1 == rhs.*member1 && lhs.*member2 < rhs.*member2);
}
private:
MemberType1 T::*member1;
MemberType2 T::*member2;
};
int main()
{
A a[] = {{1, 3}, {2, 2}, {1, 1}};
const std::size_t size = sizeof(a) / sizeof(a[0]);
std::sort(a, a + size, LessThan<A, int, int>(&A::a, &A::b));
for (std::size_t i = 0; i < size; ++i)
{
std::cout << a[i].a << ' ' << a[i].b << '\n';
}
}
how would I sort only the b data? For example,
Code:
A a[] = {{1, 3}, {3, 2}, {2, 1}};
so that the answer is {1,1}, {3, 2}, {2,3}.
-
July 2nd, 2009, 10:07 AM
#9
Re: math function on individual struct attributes in an array
It's pretty trivial to simplify that example to only use one field. Give it a try.
-
July 2nd, 2009, 10:34 AM
#10
Re: math function on individual struct attributes in an array
I had to deal with a similiar problem recently and I went this way:
First you need a functor that isolates the desired members from your data type:
Code:
struct DataExtractorA
{
double operator()( const MyData_t& data ) const
{
// application operator isolates value A
return data.dataA;
}
};
struct DataExtractorB
{
double operator()( const MyData_t& data ) const
{
// application operator isolates value B
return data.dataB;
}
};
struct DataExtractorAB
{
double operator()( const MyData_t& data ) const
{
// application operator isolates value A + value B
return data.dataA + data.dataB;
}
};
Next you need a functor object that uses an extractor functor and use the value in your calculation:
Code:
template<typename ExtractorType>
struct MedianCalculator
{
double Result_;
// Extractor instance
ExtractorType Extractor_;
MedianCalculator() : Result_( 0.0 )
{
}
// application operator
double operator()( const MyData_t& data ) const
{
// pass the data object to the extractor and let the extractor extract the desired value(s)
// pass the extracted value to the update method to update the result
update( Extractor_( data ) );
}
void update( double Value )
{
// update result
}
};
This is how it fits into your code:
Code:
vector<MyData_t> DataVector;
typedef MedianCalculator<DataExtractorA> MCA;
typedef MedianCalculator<DataExtractorAB> MCAB;
// Calculate median of A
MCA CalcA = for_each( DataVector.begin(), DataVector.end(), MCA() );
double MedianA = CalcA.Result_;
// Calculate median of A+B
MCAB CalcAB = for_each( DataVector.begin(), DataVector.end(), MCAB() );
double MedianAB = CalcAB.Result_;
This provides a flexible and extensible approach imho.
- Guido
-
July 2nd, 2009, 10:40 AM
#11
Re: math function on individual struct attributes in an array
Let me qualify my point by saying I certainly agree with concepts involving function objects, pointers to members and related techniques.
Why not simply make these separate containers? The functions would be identical, and the substitution of one "channel" of data or another is simply through the selection of the relevant container.
If my post was interesting or helpful, perhaps you would consider clicking the 'rate this post' to let me know (middle icon of the group in the upper right of the post).
-
July 2nd, 2009, 10:44 AM
#12
Re: math function on individual struct attributes in an array
 Originally Posted by GNiewerth
I had to deal with a similiar problem recently and I went this way:
First you need a functor that isolates the desired members from your data type:
Code:
struct DataExtractorA
{
double operator()( const MyData_t& data ) const
{
// application operator isolates value A
return data.dataA;
}
};
struct DataExtractorB
{
double operator()( const MyData_t& data ) const
{
// application operator isolates value B
return data.dataB;
}
};
struct DataExtractorAB
{
double operator()( const MyData_t& data ) const
{
// application operator isolates value A + value B
return data.dataA + data.dataB;
}
};
Next you need a functor object that uses an extractor functor and use the value in your calculation:
Code:
template<typename ExtractorType>
struct MedianCalculator
{
double Result_;
// Extractor instance
ExtractorType Extractor_;
MedianCalculator() : Result_( 0.0 )
{
}
// application operator
double operator()( const MyData_t& data ) const
{
// pass the data object to the extractor and let the extractor extract the desired value(s)
// pass the extracted value to the update method to update the result
update( Extractor_( data ) );
}
void update( double Value )
{
// update result
}
};
This is how it fits into your code:
Code:
vector<MyData_t> DataVector;
typedef MedianCalculator<DataExtractorA> MCA;
typedef MedianCalculator<DataExtractorAB> MCAB;
// Calculate median of A
MCA CalcA = for_each( DataVector.begin(), DataVector.end(), MCA() );
double MedianA = CalcA.Result_;
// Calculate median of A+B
MCAB CalcAB = for_each( DataVector.begin(), DataVector.end(), MCAB() );
double MedianAB = CalcAB.Result_;
This provides a flexible and extensible approach imho.
Interesting. I would make the operator() for the extractors return different types for my individual case instead of double. For the MedianCalculator operator() shouldn't it return a bool instead of a double? Not sure I understand the update() function yet...let me think abotu it some more.
-
July 2nd, 2009, 10:59 AM
#13
Re: math function on individual struct attributes in an array
 Originally Posted by JVene
Let me qualify my point by saying I certainly agree with concepts involving function objects, pointers to members and related techniques.
Why not simply make these separate containers? The functions would be identical, and the substitution of one "channel" of data or another is simply through the selection of the relevant container.
Yes I'd like to separate into multiple containers. But the data is all related by a time value (history). Which has a fair bit of processing, so I would have to duplicate that processing I think. Maybe not, trying to figure that out. Here is some of my history processing code:
Code:
struct MyData_t
{
int dataA;
int dataB;
}
struct MyOtherData_t
{
int dataA;
int dataB;
double dataC;
int dataD;
short dataE;
int dataF;
}
template <typename T, unsigned int size> class History
{
public :
struct MyHistory_t
{
T data;
long time;
}
typedef std::vector<MyHistory_t> HistoryList_t;
void AddNewElement(T element);
void DoSomething();
}
main()
{
History<MyData_t, 10> aHistory();
History<MyOtherData_t, 15> bHistory();
//add n elements to aHistory
//add n elements to bHistory
aHistory.DoSomething();
bHistory.DoSomething();
//calculate median of aHistory.dataB
//calculate median of bHistory.dataB
//calculate median of bHistory.dataC
}
Hopefully this clears some things up.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|