CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 13 of 13
  1. #1
    Join Date
    Mar 2008
    Posts
    38

    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.

  2. #2
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    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.

  3. #3
    Join Date
    Nov 2006
    Posts
    1,611

    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).

  4. #4
    Join Date
    Mar 2008
    Posts
    38

    Re: math function on individual struct attributes in an array

    Quote Originally Posted by JVene View Post
    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.

  5. #5
    Join Date
    Mar 2008
    Posts
    38

    Re: math function on individual struct attributes in an array

    Quote Originally Posted by Lindley View Post
    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.

  6. #6
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: math function on individual struct attributes in an array

    Quote 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.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  7. #7
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    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.

  8. #8
    Join Date
    Mar 2008
    Posts
    38

    Re: math function on individual struct attributes in an array

    Quote Originally Posted by laserlight View Post
    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}.

  9. #9
    Lindley is offline Elite Member Power Poster
    Join Date
    Oct 2007
    Location
    Seattle, WA
    Posts
    10,895

    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.

  10. #10
    Join Date
    Nov 2006
    Location
    Essen, Germany
    Posts
    1,344

    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

  11. #11
    Join Date
    Nov 2006
    Posts
    1,611

    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).

  12. #12
    Join Date
    Mar 2008
    Posts
    38

    Re: math function on individual struct attributes in an array

    Quote Originally Posted by GNiewerth View Post
    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.

  13. #13
    Join Date
    Mar 2008
    Posts
    38

    Re: math function on individual struct attributes in an array

    Quote Originally Posted by JVene View Post
    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
  •  





Click Here to Expand Forum to Full Width

Featured