views:

949

answers:

9

I've written a loop in C++ to give me 6 random numbers and store them in an array. What I would like to do is to sum the elements of the array until I get a value larger than a number, "x", but I would like to do this without necessarily adding all the elements. The objective is to find the first elements which sum to the value of x.

For example, array is [1,2,3,4,5,6], and x = 6, so what I would be looking for are the elements [1,2,3].

I've looked at the standard library and have tried using the sum function from "valarray" but this just gives the sum of all the elements. Any ideas on how to code this successfully would be greatly appreciated.

+7  A: 

I'm assuming you just want the first X elements in the array, up until their sum meets or exceeds a threshold (the question was a little vague there).

If so, I don't know how to do that without your own loop:

int sum = 0;
int i = 0;
for( ; i < len; ++i ) {
    sum += array[i];
    if( sum >= 6 ) {
        break;
    }
}

Now "i" contains the index at which the sum met or exceeded your threshold.

Matt Dillard
A: 

Well, i would use a vector

T addUntil(T array[],size_t len,T thres){
    vector<T> vec = vector_from_array(array,len)
    T sum;
    for (size_t i=0;i< vec.size(),sum<thresh;i++){
          sum+= vec[i];
    }
    return sum;
}

T would need operator+ and operator< to be defined.

Tom
What is the point of copying the array into a vector?
Luc Touraille
I was thinking down the lines of not passing the array's length as a parameter. Now that i see other answers, i realize this is quite poor.
Tom
Two things wrong with this: 1) It needs to be `T array[]` and 2) you have to pass the length of the array pointed to by the pointer to your `vector_from_array` function.
Johannes Schaub - litb
Thanks litb. Java is seriously ruining my c++ skills.
Tom
+11  A: 

Write a functor that does the addition.

#include <algorithm>
struct SumToo
{
     SumToo(int val):m_val(val),m_sum(0) {}
     int m_val;
     int m_sum;

     bool operator()(int next)
     {
         m_sum += next;
         return m_sum >= m_val;
     }
 };

 int main()
 {
       int data[] = {1,2,3,4,5,6};

       int* find = std::find_if(data,data+6,SumToo(6));
 }
Martin York
every time i think of functors, i despise Java a little more (currently java programmer :( )
Tom
Questioner wants a value larger than x, not equal to x.
Thomas L Holaday
-1: Predicate functors should not have non-static data fields (https://www.securecoding.cert.org/confluence/display/cplusplus/ARR44-CPP.+Predicate+functors+should+not+have+non-static+data+fields) or am I missing something?
stephan
See: http://www.sgi.com/tech/stl/table_of_contents.html Mutating algorithms are more complex non mutating algorithms. Thus things like remove_if object should not hold sate while non mutating algorithms (like find_if) are much simpler and will be OK. Though I don't have any specific standard reference saying which is valid where (apart form tests).
Martin York
Hmmm, `find_if` does not guarantee an order of execution (25.1.2 of the standard). While I agree that your version works on most implementations, it introduces a bug if `find_if` does not progress sequentially. Take gcc's parallel `find_if` (http://gcc.gnu.org/onlinedocs/libstdc++/manual/parallel_mode.html): it splits the range into n blocks and searches the blocks in parallel. See `__find_template`: http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a00875_source.html. Hence, a bug is only a compiler-flag `-D_GLIBCXX_PARALLEL -fopenmp` away (ignoring the additional race-condition).
stephan
@Stephan: Bugs are always on step away when you use non standard compiler flags/extensions. Actually 25.1.2 does guarantee an order. (Look up Input Iterator definition (elements can only be accessed in order)).
Martin York
I politely disagree. IIRC, 1) ... `for_each` and some algorithms in `<numerics>` guarantee order, but not `find_if`. The standard allows for specializations of algorithms for e.g. random access iterators. 2) ... while not all of gcc's parallel-mode stl algorithms are conforming, I believe `find_if` to be so, because its observable behavior fulfils the standard's requirements. Not 100% sure though regarding all this, hence I might open a question on SO after some more thinking. Thanks for the discussion.
stephan
@stephan: You are correct the order the functor is applied is not guaranteed. But the Input Iterator only allows sequential accesses (and you must read the value before moving to the next one (otherwise it is gone) and you can't move past the found item (as you must return the iterator and you can't get back if you move past it)). But if you happen to have random access iterator then of course you could do it any order. Do you have a reference to the standard about specializing algorithms based on iterator types (for future reference).
Martin York
I don't have a reference other than my understanding of "observed behavior" and some evidence. Stepanov often mentions specialization (e.g. http://www.sgi.com/tech/stl/drdobbs-interview.html) and implementations do it, e.g. `std::fill` calling `memset` for `char`. Why should it not be allowed to specialize on iterator type? Furthermore, the standard clearly spells out order where important, e.g. in `std::copy` to allow overlap. From this I follow that the implementation is free to choose order based on iterator type unless order is defined. I cannot offer more than this reasoning.
stephan
@stephan: These are specializations of the value_type (not the iterator). For std::copy the order is only mentioned because the two ranges may overlap and the implementers wanted to make sure the operation was well defined.
Martin York
A: 

would be something like:

struct StopAtValue{
  StopAtValue(int sum) : m_sum(sum), m_accumulated(0){}
  bool operator()(int val){
    m_accumulated += val;
    return m_accumulated >= sum;
  }
  int m_sum;
  int m_accumulated;
}


int* pos = std::find_if(&array[0], &array[n], StopAtValue(6));
Viktor Sehr
A: 

You could use std::find_if() along with a functor that maintains a running total, and only returtn true from the functor when you have found the element that puts you at or over the top.

For example:

#include <cstdlib>
#include <algorithm>
#include <functional>
#include <iostream>
#include <string>
using namespace std;

// functor returns true when the running total >= findVal
struct running_total : public unary_function<int, bool>
{
    running_total(int findVal) : findVal_(findVal), runningTtl_(0) {};
    bool operator()(int rhs) const
    {
     runningTtl_ += rhs;
     if( runningTtl_ >= findVal_ )
      return true;
     else
      return false;
    }
private:
    mutable int runningTtl_;
    const int findVal_;
};

int main()
{

    int nums[] = {1, 2, 3, 4, 5, 6};
    size_t count = sizeof(nums)/sizeof(nums[0]);

    const int scanTtl = 6; // running total to scan to
    int * pos = find_if(&nums[0], &nums[0]+count, running_total(scanTtl));

    cout << "Elements Totaling " << scanTtl << " : ";
    copy(&nums[0], pos+1, ostream_iterator<int>(cout, ", "));

    return 0;
}
John Dibling
+2  A: 

Substract the numbers from x one by one, until you reach 0 or lower.

No additions, as you wished :)

Daniel Daranas
+1  A: 

Here's a slightly more generic version:

#include <iostream>
#include <algorithm>

// return an iterator _Last such that sum 
// of all elements in the range [_First, _Last)
// satisfies the predicate Func
template<class InIt,
class Ty,
class Fn> inline
InIt accumulate_if(InIt First, InIt Last, Ty Val, Fn Func)
{ 
    for (; Func(Val) && First != Last; ++First)
     Val = Val + *First;
    return (First);
}

int main() {
    int num[] = {1, 2, 3, 4, 5, 6};
    int *last = accumulate_if(num, num + sizeof num / sizeof num[ 0 ], 
                              0, std::bind2nd(std::less<int>(), 6));
    std::copy(num, last, std::ostream_iterator<int>(std::cout, "\n"));
    return 0;
}
dirkgently
A: 

Here's hoping this works:

/* Returns an index i, given array valarray[0,1..n] and number x where i is an index to valarry such that sum over j of valarray[j] for j = 0 to i > x */
int getFirstSum(int *valarray, int n, int x)
{
   int i = 0;
   int sum = x;
   while(sum > x && i < n)
   {
      i++;
      sum -= valarray[i];
   }
   return i;
}
royrules22
+3  A: 

Avoid the answers that suggest using find_if with a stateful predicate. Stateful predicates are dangerous as the STL algorithms assume it is safe to copy predicates. In this case, if copies are made of the predicate then each will have a different 'running total' and will not necessarily act on all values, or in the correct order.

Especially avoid the solution that implements its predicate's operator() member as a const member function but labels its members as mutable as this is fooling you into thinking it is not a stateful predicate, which is bad.

I'd suggest using either one of the answers that simply loops to find the answer, or the answer that uses an accumulator, as that is the most correct way to do it (even if the code looks a little unwieldy.

Note that the warnings may well not apply to C arrays and find_if; I just don't want you to learn that stateful predicates are the right way to solve your problem since you may end up using that incorrect solution in a situation where it is dangerous in future.

Reference: C++ Coding Standards: 101 Rules, Guidelines, and Best Practices, Item 87

Ben Hymers