3
\$\begingroup\$

In this question, I need to find the sum of 2 arrays element by element. Arrays can be of unequal length.

Explanation: Sum of [1, 0, 2, 9] and [3, 4, 5, 6, 7] is [3, 5, 5, 9, 6] and the first digit represents carry over , if any (0 here ).

Here's what I could come up with. Let me know if anything could be done better,or anything i did wrong.

Also earlier someone suggested me that I should split my code into smaller pieces that are easier to read and test individually. Perhaps if anyone could help with the method signatures that I should make(if any).

    private static void sum(int[] arr1, int[] arr2) {
    ArrayList<Integer> arraySum = new ArrayList<>();
    int[] largerArray, smallerArray;
    boolean flag;
    if (arr1.length == arr2.length) {
        largerArray = arr1;
        smallerArray = arr2;
        flag = true;
    } else if (arr1.length > arr2.length) {
        largerArray = arr1;
        smallerArray = arr2;
        flag = false;
    } else {
        largerArray = arr2;
        smallerArray = arr1;
        flag = false;
    }
    int sum = 0, carry = 0;
    int diff = largerArray.length - smallerArray.length;
    for (int i = smallerArray.length - 1; i >= 0; i--) {        //traverse through smaller array
        sum = largerArray[i + diff] + smallerArray[i] + carry;
        carry = 0;
        if (sum > 9) {
            int N = sum;
            while (N != 0) {
                int rem = N % 10;
                if (N < 10) {
                    carry = rem;
                } else {
                    arraySum.add(rem);
                }
                if (i == 0 && carry != 0 && flag) {     //if we are at last element & carry!=0 add carry as first digit
                    arraySum.add(carry);
                }
                N = N / 10;
            }
        } else {
            arraySum.add(sum);
        }
    }
    if (!flag) {
        for (int i = diff - 1; i >= 0; i--) {       // now sum remaining elements of larger array
            sum = arr1[i] + carry;
            carry = 0;
            if (sum > 9) {
                int N = sum;
                while (N != 0) {
                    int rem = N % 10;
                    if (N < 10) {
                        carry = rem;
                    } else {
                        arraySum.add(rem);
                    }
                    if (i == 0 && carry != 0) {     //if we are at last element & carry!=0 add carry as first digit
                        arraySum.add(carry);
                    }
                    N = N / 10;
                }
            } else {
                arraySum.add(sum);
            }
        }
    }
    display(arraySum);
}
\$\endgroup\$
2
  • \$\begingroup\$ "Perhaps if anyone could help with the method signatures that I should make(if any)" Doesn't your IDE suggest these, when you select a block of code and choose Refactor from the context menu? \$\endgroup\$ Jan 28 '17 at 12:33
  • \$\begingroup\$ @πάνταῥεῖ Its been only a week or two since I started learning programming(java being my first language), so I am not aware of all the MAGIC my IDE could do. Thanks for the info anyways. \$\endgroup\$
    – user129118
    Jan 28 '17 at 12:55
2
\$\begingroup\$

Instead of reviewing your code as is, I'll propose an alternative solution that should be a tad simpler than yours:

We don't need to know which array of the two is the larger, we only need our result array to be able to contain it:

int[] result = new int[Math.max(arr1.length, arr2.length) + 1];

Note that we need an extra element to adjust for possible "overflow" (aka. carry in the last added digit).

Now since we need to sum things, let's just copy over one of the two arrays into our result:

System.arraycopy(arr1, 0, result, result.length - arr1.length, arr1.length);

Now the only thing that remains to be done is doing the addition with the other array. We'll need something to store the carry in. Luckily by nature of a carry, it's maximum value is always 1 (it seems you didn't notice that). So we either have a carry-flag or not:

boolean carry = false;

Now let's walk the other array, and perform the addition. Note that I use the conventional iteration indexing \$\{1,\ldots,length-1\}\$ instead of the backwards indexing you used to simplify the reasoning in the addition:

for (int i = 0; i < arr2.length; i++) {
    int digitResult = result[result.length - 1 - i] + arr2[arr2.length - 1 - i];
    // usually you'd write this on properly separate lines
    if (carry) { digitResult += 1; }
    if (digitResult >= 10) {
        carry = true;
        digitResult -= 10;
    } else {
        carry = false;
    }
    result[result.length - 1  - i] = digitResult;
}

This was the "interesting part" already. The only thing remaining to be done is cleaning up a possibly remaining carry:

int i = arr2.length;
while (carry) {
    int r = result[result.length - 1 - i] + 1;
    if (r >= 10) { // could also be == 10
        r -= 10;
    } else {
        carry = false;
    }
    result[result.length - 1 - i] = r;
    i++;
}

Theoretically we might need to check the array access, but it's mathematically provable we don't need to, so I won't do checks. An explanatory comment could help for doing that.

Now as Timothy Truckle already mentioned in his answer your method is responsible for too many things. You should at this point just return the result array to the caller, and that's the extent of the method.

There's some repetition and "uncleanliness" in this code, that I left in on purpose. I'm pretty sure with some thinking you should be able to clean the code up a bit, and it's hard to learn it just from a person telling you what's wrong. Find out :)

\$\endgroup\$
1
\$\begingroup\$

You can use an ArrayList instead of an array and implement a normal addition method to it. Here is the function. Check it out ;)

public static ArrayList<Integer> sum(int[] arr, int[] arr2) {
    ArrayList<Integer> al = new ArrayList<>();
    int i = arr.length - 1;
    int j = arr2.length - 1;
    int c = 0;
    while (i >= 0 && j >= 0) {
        int temp = arr[i] + arr2[j] + c;
        if (temp >= 10) {
            int r = temp % 10;
            al.add(0, r);
            c = temp / 10;
        } else {
            al.add(0, temp);
            c = 0;
        }
        i--;
        j--;
    }
    if (i < 0 && j >= 0) {
        while (j >= 0) {
            al.add(0, arr2[j] + c);
            c = 0;
            j--;
        }
    } else if (j < 0 && i >= 0) {
        while (i >= 0) {
            al.add(0, arr[i] + c);
            c = 0;
            i--;
        }

    } else
        al.add(0, c);
    return al;
}
\$\endgroup\$
0
\$\begingroup\$

separation of concerns

Your method fails to separate concerns. Beside doing the sum it also displays the result. Instead of calling display(arraySum); it should return the resulting array.

naming

You have poorly named variables:

  • the name of the method sum is ambiguous. There are many how tho sum arrays. This should better be addArraysAsBinaryCodeDecimal since that is what your method does (for the nitpickers: I know that BCD are strictly something else...)
  • what exactly does flag signal?
  • what is N? also this should be at least a lower case n to follow Java naming conventions.
  • and what is rem

DRY

The logic for summing is duplicated with only a small variation
(if (i == 0 && carry != 0 && flag) vs (i == 0 && carry != 0)

You could make both blocks the same and extract them to a new method:

private int addDigit(int sum,  ArrayList<Integer> arraySum, boolean flag ){
    int carry = 0;
    if (sum > 9) {
        int N = sum;
        while (N != 0) {
            int rem = N % 10;
            if (N < 10) {
                carry = rem;
            } else {
                arraySum.add(rem);
            }
            if (i == 0 && carry != 0 && flag) {     //if we are at last element & carry!=0 add carry as first digit
                arraySum.add(carry);
            }
            N = N / 10;
        }
    } else {
        arraySum.add(sum);
    }
    return carry;
 }

 private static void sum(int[] arr1, int[] arr2) {
 //  ...
    for (int i = smallerArray.length - 1; i >= 0; i--) {        //traverse through smaller array
        sum = largerArray[i + diff] + smallerArray[i] + carry;
        carry = addDigit(sum, arraySum, flag);
    }
    if (!flag) {
        for (int i = diff - 1; i >= 0; i--) {       // now sum remaining elements of larger array
            sum = arr1[i] + carry;
            carry = addDigit(sum, arraySum, true);
        }
    }
 }
\$\endgroup\$
4
  • \$\begingroup\$ the review looked nice, until the moment you hacked ArrayList<Integer> into addDigit for no discernible reason :/ \$\endgroup\$
    – Vogel612
    Jan 28 '17 at 13:29
  • \$\begingroup\$ @Vogel612 what do you mean by "for no reason"? the list must be passed to the method so that the resulting digits can be added. \$\endgroup\$ Jan 28 '17 at 14:05
  • \$\begingroup\$ no it doesn't ... it's not necessary to use a list in the first place. also you could just return the digit from the method ... or you could extract a method that does less things at once :) \$\endgroup\$
    – Vogel612
    Jan 28 '17 at 14:12
  • \$\begingroup\$ @Vogel612 "it's not necessary to use a list in the first place." while this is true it was the OPs choice, not mine... Feel free to point that in your own answer. \$\endgroup\$ Jan 28 '17 at 14:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy