0

I want to have a function that returns the sum of different (non duplicate) values from an array: if I have {3, 3, 1, 5}, I want to have sum of 3 + 1 + 5 = 9.

My attempt was:

int sumdiff(int* t, int size){
    int sum=0;
    for (int i=0; i<=size;i++){
        for(int j=i; j<=size;j++){
            if(t[i]!=t[j])
            sum=sum+t[i];
        }
    }
    return sum;
}

int main()
{
    int t[4]={3, 3, 1, 5};
    cout << sumdiff(t, 4);
}

It returns 25 and I think I know why, but I do not know how to improve it. What should I change?

Mroweczka
  • 59
  • 9

6 Answers6

2

Put all the items in a set, then count them.

Sets are data structures that hold only one element of each value (i.e., each of their elements is unique; if you try to add the same value more than once, only one instance will be count).

You can take a look in this interesting question about the most elegant way of doing that for ints.

Community
  • 1
  • 1
Mike
  • 1,215
  • 7
  • 12
  • 1
    Maybe expand your answer a little bit? – Rakete1111 Nov 22 '16 at 09:23
  • I would appreciate. – Mroweczka Nov 22 '16 at 09:25
  • Wow, that was super quick, Mike :) – Vada Poché Nov 22 '16 at 09:26
  • I have elaborated it a bit, HTH. – Mike Nov 22 '16 at 09:29
  • But could it be done in a way similar to what i wanted to do? – Mroweczka Nov 22 '16 at 09:30
  • @Mroweczka - *But could it be done in a way similar to what i wanted to do?* -- Think on a higher abstraction. The goal is to ensure that you write code that doesn't have bugs. If you google "Sean Parent" and look at his talks on C++, you will see the benefit of eliminating or minimizing writing hand-coded `for` loops. There is little to no chance of a bug occurring with this answer and other answers that acknowledge usage of `std::set`. – PaulMcKenzie Nov 22 '16 at 10:17
  • Thanks, understood. i just wanted to know whether it is possible to go after my initial way of thinking. – Mroweczka Nov 22 '16 at 10:20
  • @Mroweczka -- However if you look at your attempt,,it is very inefficient. You have a nested `for` loop over the entire dataset, thus you;re potentially looping n*n times. In other words, if you have 1,000 numbers, you are looping a million times. Using a `std::set` or `std::unordered_set`, the efficiency is improved, since insertion into a set is logarithmic. So you're not only buying bug free code, you're also buying more efficient code using a set. – PaulMcKenzie Nov 22 '16 at 10:26
  • I am aware of that. Appreciate your help. – Mroweczka Nov 22 '16 at 10:31
1

First of all, your loop should be for (int i=0; i<size;i++). Your actual code is accessing out of the bounds of the array.

Then, if you don't want to use STL containers and algorithms (but you should), you can modify your code as follows:

int sumdiff(int* t, int size){
    int sum=0;
    for (int i=0; i<size;i++){

        // check if the value was previously added

        bool should_sum = true;

        for(int j=0; should_sum && j<i;j++){
            if(t[i]==t[j])
                should_sum = false;
        }

        if(should_sum)
            sum=sum+t[i];
    }
    return sum;
}

int main()
{
    int t[4]={3, 3, 1, 5};
    cout << sumdiff(t, 4);
}
rocambille
  • 15,398
  • 12
  • 50
  • 68
0

You could:

  • Store your array contents into an std::unordered_set first. By doing so, you'd essentially get rid of the duplicates automatically.
  • Then call std::accumulate to compute the sum
  • Vada Poché
    • 763
    • 5
    • 16
    0

    **wasthishelpful's answer was exactly what i was talking about. I saw his post after i posted mine.

    So, you're trying to check the duplicate number using your inner loop. However, your outer loop will loop 4 times no matter what which gives you wrong result. Try,

    • Do only checking in inner loop. (use a flag to record if false)
    • Do your sum outside of inner loop. (do the sum when flag is true)
    Chang Sheng
    • 110
    • 6
    0

    Insert array elements into a set and use the std::accumulate function:

    #include <iostream>
    #include <numeric>
    #include <set>
    
    int main()
    {
        int t[4] = { 3, 3, 1, 5 };
        std::set<int> mySet(std::begin(t), std::end(t));
        int mySum = std::accumulate(mySet.begin(), mySet.end(), 0);
        std::cout << "The sum is: " << mySum << std::endl;
        return 0;
    }
    
    0

    Here is another solution using std::accumulate, but it iterates over the original elements in the call to std::accumulate, and builds the set and keeps a running total as each number in the array is encountered:

    #include <iostream>
    #include <numeric>
    #include <set>
    
    int main()
    {
        int t[4] = { 3, 3, 1, 5 };
        std::set<int> mySet;
        int mySum = std::accumulate(std::begin(t), std::end(t), 0, 
             [&](int n, int n2){return n += mySet.insert(n2).second?n2:0;});
        std::cout << "The sum is: " << mySum << std::endl;
        return 0;
    }
    

    The way it works is that std::insert() will return a pair tbat determines if the item was inserted. The second of the pair is a bool that denotes whether the item was inserted in the set. We only add onto the total if the insertion is successful, otherwise we add 0.

    Live Example

    PaulMcKenzie
    • 34,698
    • 4
    • 24
    • 45
    • `const std::set mySet{std::begin(t), std::end(t)}; const int mySum = std::accumulate(std::begin(t), std::end(t), 0);` seems more natural/simpler. – Jarod42 Nov 22 '16 at 10:13