Related
I have made a simple program that performs basic arithmetic operations on all the elements of a given array. But the problem is that the code is very repetitive and it's not a good practice to write repeated code and I can't come up with a solution to this problem.
How can we minimize code repetition in this program?
int add(int numcount, int numarr[]){
int total = numarr[0];
// add all the numbers in a array
for (int i = 1; i < numcount; i++){
total += numarr[i];
}
return total;
}
int sub(int numcount, int numarr[]) {
int total = numarr[0];
// subtract all the numbers in array
for (int i = 1; i < numcount; i++){
total -= numarr[i];
}
return total;
}
int mul(int numcount, int numarr[]) {
int total = numarr[0];
// multiply all the numbers in array
for (int i = 1; i < numcount; i++){
total *= numarr[i];
}
return total;
}
int main(int argc, char* argv[]){
const int n = 5;
int arr[n] = {1, 2, 3, 4, 5};
cout << "Addition: " << add(n, arr) << endl;
cout << "Subtraction: " << sub(n, arr) << endl;
cout << "Multiplication: " << mul(n, arr) << endl;
}
How can we minimize code repetition in this program?
Generically, by identifying the repeated structure and seeing whether we can either abstract it out, or find an existing name for it.
The repeated structure is just setting the running result to the first element of a container, and using a binary function to combine it with each subsequent element in turn.
Take a look at the Standard Algorithms library and see if any existing function looks similar
std::accumulate can do what we need, without any extra arguments for the add, and with just the appropriate operator function object for the others
So, you can trivially write
int add(int numcount, int numarr[]){
return std::accumulate(numarr, numarr+numcount, 0);
}
// OK, your sub isn't actually trivial
int sub(int numcount, int numarr[]){
return std::accumulate(numarr+1, numarr+numcount, numarr[0],
std::minus<int>{});
}
// could also be this - honestly it's a little hairy
// and making it behave well with an empty array
// requires an extra check. Yuck.
int sub2(int numcount, int numarr[]){
return numarr[0] - add(numcount-1, numarr+1);
}
etc.
It would be slightly nicer to switch to using std::array, or to use ranges if you're allowed C++20 (to abstract iterator pairs over all containers).
If you must use C arrays (and they're not decaying to a pointer on their way through another function), you could write
template <std::size_t N>
int add(int (&numarr)[N]){
return std::accumulate(numarr, numarr+N, 0);
}
to save a bit of boilerplate (passing numcount everywhere is just an opportunity to get it wrong).
NB. as mentioned in the linked docs, std::accumulate is an implementation of a left fold. So, if the standard library didn't provide accumulate, there's still an existing description of the "thing" (the particular "higher-order function") we're abstracting out of the original code, and you could write your own foldl template function taking the same std::plus, std::minus etc. operator functors.
You can use std::accumulate:
auto adder = [](auto accu,auto elem) { return accu + elem; };
auto multiplier = [](auto accu, auto elem) { return accu * elem; };
auto sum = std::accumulate(std::begin(arr),std::end(arr),0,adder);
auto prod = std::accumulate(std::begin(arr),std::end(arr),0,multiplier);
The result of sub is just 2*arr[0] - sum.
Be careful with the inital value for std::accumulate. It determines the return type and multiplying lots of int can easily overflow, perhaps use 0LL rather than 0.
In cases where std::accumulate nor any other standard algorithm fits, and you find yourself writing very similar functions that only differ by one particular operation, you can refactor to pass a functor to one function that lets the caller specifiy what operation to apply:
template <typename F>
void foo(F f) {
std::cout << f(42);
}
int identity(int x) { return x;}
int main() {
foo([](int x) { return x;});
foo(identity);
}
Here foo prints to the console the result of calling some callable with parameter 42. main calls it once with a lambda expression and once with a free function.
How can we minimize code repetition in this program?
One way to do this is to have a parameter of type char representing the operation that needs to be done as shown below:
//second parameter denotes the operator which can be +, - or *
int calc(int numcount, char oper, int numarr[])
{
//do check here that we don't go out of bounds
assert(numcount > 0);
int total = numarr[0];
// do the operatations for all the numbers in the array
for (int i = 1; i < numcount; i++){
total = (oper == '-') * (total - numarr[i]) +
(oper == '+') * (total + numarr[i]) +
(oper == '*') * (total * numarr[i]);
}
return total;
}
int main()
{
int arr[] = {1,2,3,4,5,6};
std::cout << calc(6, '+', arr) << std::endl; //prints 21
std::cout << calc(6, '-', arr) << std::endl; //prints -19
std::cout << calc(6, '*', arr) << std::endl; //prints 720
}
Working demo
First of all, I don't want to use sort. This is just an illustration example. The main purpose of this question is that I want to:
find all possible combinations of m numbers out of n numbers and
process them, then return the unique processed result (since the
processed results of all possible combinations will be compared).
Question start at here
The following code get all possible combinations M numbers out of N numbers. Sum the M numbers and find the largest sum. In doing this I used a recursion function.
However, it seems that I must define a global variable to store the temporary largest sum. Is there any way to get rid of this global variable? For example, define the recursion function to return the largest sum... I don't want the global variable just become an argument &max_sum in the find_sum, since find_sum already have too many arguments.
#include <iostream>
#include <vector>
void find_sum(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start);
int max_sum =0;
int main() {
int N = 10;
int M = 3;
std::vector<int> ar(N);
ar = {0,9,2,3,7,6,1,4,5,8};
int index = 0, start =0;
std::vector<int> combine(M);
find_sum(ar, combine, index, start);
std::cout << max_sum <<std::endl;
return 0;
}
void find_sum(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start) {
if(index == combine.size()) {
int sum =0;
for(int i=0; i<index; ++i) {
sum += combine[i];
}
if(max_sum < sum) {
max_sum = sum;
}
return ;
}
for(int i = start;
i < ar.size() && ar.size()-i > combine.size()-index;
++i) {
combine[index] = ar[i];
find_sum(ar, combine, index+1, start+1);
}
}
An approach that scales well is to turn find_sum into a function object. The trick is to define a struct with an overloaded () operator that takes a certain set of parameters:
struct FindSum
{
void operator()(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start){
/*ToDo - write the function here, a very explicit way of
/*engineering the recursion is to use this->operator()(...)*/
}
int max_sum; // I am now a member variable
};
Then instantiate FindSum find_sum;, set find_sum.max_sum if needed (perhaps even do that in a constructor), then call the overloaded () operator using find_sum(...).
This technique allows you to pass state into what essentially is a function.
From find_sum, return the so-far maximum sum (instead of void). That means that the recursion-terminating code would be:
if(index == combine.size()) {
int sum =0;
for(int i=0; i<index; ++i) {
sum += combine[i];
}
return sum;
}
and the recursive part would be
int max_sum = 0;
for(int i = start;
i < ar.size() && ar.size()-i > combine.size()-index;
++i) {
combine[index] = ar[i];
int thismaxsum = find_sum(ar, combine, index+1, start+1);
if(thismaxssum > max_sum)
max_sum = thismaxsum;
}
return max_sum;
So, the overall solution is:
#include <iostream>
#include <vector>
int find_sum(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start);
int main() {
int N = 10;
int M = 3;
std::vector<int> ar(N);
ar = { 0,9,2,3,7,6,1,4,5,8 };
int index = 0, start = 0;
std::vector<int> combine(M);
int max_sum = find_sum(ar, combine, index, start);
std::cout << max_sum << std::endl;
return 0;
}
int find_sum(const std::vector<int>& ar, std::vector<int>& combine,
int index, int start)
{
if (index == combine.size())
{
int sum = 0;
for (int i = 0; i<index; ++i)
{
sum += combine[i];
}
return sum;
}
int max_sum = 0;
for (int i = start;
i < ar.size() && ar.size() - i > combine.size() - index;
++i)
{
combine[index] = ar[i];
int thismaxsum = find_sum(ar, combine, index + 1, start + 1);
if (thismaxsum > max_sum)
max_sum = thismaxsum;
}
return max_sum;
}
Global variables are much better then adding operands and variables to recursion functions because each operand and variable causes heap/stack trashing negatively impact performance and space usage risking stack overflow for higher recursions.
To avoid global variables (for code cosmetics and multi threading/instancing purposes) I usually use context or temp struct. For example like this:
// context type
struct f1_context
{
// here goes any former global variables and stuff you need
int n;
};
// recursive sub function
int f1_recursive(f1_context &ctx)
{
if (ctx.n==0) return 0;
if (ctx.n==1) return 1;
ctx.n--;
return (ctx.n+1)*f1_recursive(ctx.n);
}
// main API function call
int f1(int n)
{
// init context
f1_context ctx;
ctx.n=n;
// start recursion
return f1_recursion(ctx);
}
the f1(n) is factorial example. This way the operands are limited to single pointer to structure. Of coarse you can add any recursion tail operands after the context... the context is just for global and persistent stuff (even if I did use it for the recursion tail instead but that is not always possible).
I've been used to using Python or Matlab where I could create a list like:
min = 5;
step = 2;
max = 16;
Range = min:step:max;
and Range would be the list [5,7,9,11,13,15].
Is there an equivalently simple way to generate a list like "Range" in C++? So far the simplest thing I can think of is using a for loop but that is comparatively quite tedious.
C++ doesn't supply such a thing, either in the language or the standard library. I'd write a function template to look (roughly) like something from the standard library, something on this order:
namespace stdx {
template <class FwdIt, class T>
void iota_n(FwdIt b, size_t count, T val = T(), T step = T(1)) {
for (; count; --count, ++b, val += step)
*b = val;
}
}
From there it would look something like this:
std::vector<int> numbers;
stdx::iota_n(std::back_inserter(numbers), 6, 5, 2);
You'll have to implement that yourself, something like this:
std::vector<int> createArray( int min, int max, int step )
{
std::vector<int> array;
for( int i = min; i < max; i += step )
{
array.push_back( i );
}
return array;
}
There is no such predefine method in C++ for this purpose.
Below code may help you.
std::vector<int> createArrayRange( int min, int max, int step )
{
std::vector<int> array;
for( int i = min; i < max; i += step )
{
array.push_back(i);
}
return array
}
Or This would be comparatively faster.
void createArrayRange( std::vector<int>& array, int min, int max, int step )
{
for( int i = min; i < max; i += step )
{
array.push_back(i);
}
}
int main()
{
std::vector<int> array;
createArrayRange(array, min, max, step);
return 0;
}
You can use std::generate for this.
std::vector< int > createArray( int min, int max, int step )
{
std::vector< int > array((max-min)/step);
int n = min;
std::generate(array.begin(), array.end(),
[&]()
{
int res = n;
n+=step;
return res;
});
return array;
}
No explicit loops needed:
vector<int> data(6,2);
data[0] = 5;
std::partial_sum(data.begin(),data.end(),data.begin());
Instead of typing
array[0] + array[1] //.....(and so on)
is there a way to add up all the numbers in an array? The language I'm using would be c++
I want to be able to do it with less typing than I would if I just typed it all out.
Here is the idiomatic way of doing this in C++:
int a[] = {1, 3, 5, 7, 9};
int total = accumulate(begin(a), end(a), 0, plus<int>());
Note, this example assumes you have somewhere:
#include <numeric>
using namespace std;
Also see: accumulate docs and accumulate demo.
Say you have an int array[N].
You can simply do:
int sum = 0;
for(auto& num : array)
sum += num;
Try this:
int array[] = {3, 2, 1, 4};
int sum = 0;
for (int i = 0; i < 4; i++) {
sum = sum + array[i];
}
std::cout << sum << std::endl;
If you use a valarray, there is a member function sum() for that.
#include <iostream> // std::cout
#include <valarray> // std::valarray
int main () {
std::valarray<int> myvalarray(4);
myvalarray[0] = 0;
myvalarray[1] = 10;
myvalarray[2] = 20;
myvalarray[3] = 30;
std::cout << "The sum is " << myvalarray.sum() << '\n';
return 0;
}
The easiest way I can see to do this is to use a loop. The bonus is that you can use it on any integer array without rewriting much code at all. I use Java more often, so I hope there aren't too many syntax errors, but something like this should work:
int addArray(int[] array, int length){
int sum=0;
for(int count=0;count<length;count++){
sum+=array[count];
}
return sum;
}
In C++17, one could use fold expressions:
template<typename ...Ts>
int sum_impl(Ts&& ...a)
{
return (a + ...);
}
If sum_impl had a constant number of parameters, we could have called it like this:
std::apply(sum_impl, arr);
assuming arr is std::array<int, N>. But since it is variadic, it needs a little push with helpers:
using namespace std;
template <class Array, size_t... I>
int sum_impl(Array&& a, index_sequence<I...>)
{
return sum_impl(get<I>(forward<Array>(a))...);
}
template <class Array>
int sum(Array&& a)
{
return sum_impl(forward<Array>(a),
make_index_sequence<tuple_size_v<decay_t<Array>>>{});
}
Therefore, assuming these helpers are in place, the code will look something like this:
template<typename ...Ts>
int sum_impl(Ts&& ...a)
{
return (a + ...);
}
int main()
{
array<int, 10> arr{0,1,2,3,4,5,6,7,8,9};
cout << sum(arr) << "\n";
return 0;
}
We may use user defined function.
Code Snippet :
#include<bits/stdc++.h>
using namespace std;
int sum(int arr[], int n)
{
int sum=0;
for(int i=0; i<n; i++)
{
sum += arr[i];
}
return sum;
}
int main()
{
int arr[] = {1, 2, 3, 4, 5};
int n = distance(begin(arr), end(arr));
int total = sum(arr,n);
printf("%d", total);
return 0;
}
int Sum;
for(int& S: List) Sum += S;
If your compiler supports c++17, you may use a combination of Parameter pack and fold expression to achieve this. A template parameter pack is a template parameter that accepts zero or more template arguments, and fold reduces the parameter pack over a binary operator. (+ in this case)
#include <iostream>
#include <array>
#include <utility>
/*
* References:
* [1] https://en.cppreference.com/w/cpp/language/fold
* [2] https://en.cppreference.com/w/cpp/language/parameter_pack
*/
template <typename ...T>
auto sum(T ...args)
{
return (args + ...);
}
template <typename T, std::size_t ...Is>
auto sum(T t, std::index_sequence<Is...>)
{
return sum(t[Is]...);
}
int main()
{
std::array<int, 3> a1 = {1, 4, 3};
int a2[5] = {1, 2, 3, 4, 0};
std::cout << "Sum a1 = " << sum(a1, std::make_index_sequence<a1.size()>{}) << "\n";
std::cout << "Sum a2 = " << sum(a2, std::make_index_sequence<5>{}) << "\n";
return 0;
}
Adding one more point regarding std::accumulate usage:
When a C-style array is passed to a function then you should explicitly specify the array start and end(one-past-the-end) addresses when you use the std::accumulate.
Example:
#include <numeric>
void outsideFun(int arr[], int n) {
int sz = sizeof arr / sizeof arr[0]; // 1=decays to a ptr to the 1st element of the arr
// int sum = accumulate(begin(arr), end(arr), 0); // Error:begin/end wouldn't work here
int sum = accumulate(arr, arr + n, 0); // 15 (Method 2 Only works!)
std::cout << sum;
}
int main() {
int arr[] = { 1,2,3,4,5 };
int sz = sizeof arr / sizeof arr[0]; // 5
int sum = accumulate(begin(arr), end(arr), 0); // 15 (Method 1 - works)
int cum = accumulate(arr, arr + sz, 0); // 15 (Method 2 - works)
outsideFun(arr, sz);
}
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.
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));
}
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.
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
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;
}
Substract the numbers from x one by one, until you reach 0 or lower.
No additions, as you wished :)
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;
}
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));
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.
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;
}