20
\$\begingroup\$

You are given a multi-dimensional array of integers. Each dimension has a fixed size (so that it would be always rectangular if it is 2D). Your program should calculate the sums in each dimension and append the sums as the new last items in that dimension.

Assume the input and output arrays are A and B, and the size of dimension i of A is ni. B would have the same number of dimensions as A and the size of dimension i would be ni+1. Bj1,j2,...,jm is the sum of Ak1,k2,...,km where:

  • ki = ji if ji <= ni
  • 0 < ki <= ni if ji = ni+1

For the input:

[[1 2 3]
 [4 5 6]]

Your program (or function) should output:

[[1 2 3 6]
 [4 5 6 15]
 [5 7 9 21]]

The input contains only the array. The total number of dimensions and the size of each dimension are not given in the input. (But you can get them from the array by your own code.) You can use any convenient list formats in your language, as long as it doesn't specify the number of dimensions or dimension sizes directly.

The input has at least 1 dimension, and has at least 1 item in the array.

This is code-golf. Shortest code wins.

Test cases

Input:
[5 2 3]
Output:
[5 2 3 10]

Input:
[[1 2 3] [4 5 6]]
Outputs:
[[1 2 3 6] [4 5 6 15] [5 7 9 21]]

Input:
[[[1] [1] [1] [0]]]
Output:
[[[1 1] [1 1] [1 1] [0 0] [3 3]] [[1 1] [1 1] [1 1] [0 0] [3 3]]]

Input:
[[[[-1]]]]
Output:
[[[[-1 -1] [-1 -1]] [[-1 -1] [-1 -1]]] [[[-1 -1] [-1 -1]] [[-1 -1] [-1 -1]]]]
\$\endgroup\$
  • \$\begingroup\$ Will you post that 16 byte APL solution? If you won't, can I? \$\endgroup\$ – Dennis May 22 '15 at 21:51
  • \$\begingroup\$ @Dennis You should post it. \$\endgroup\$ – jimmy23013 May 22 '15 at 21:51
9
\$\begingroup\$

J, 14 bytes

#@$(0|:],+/^:)

Usage:

   ]a=.i.2 3
0 1 2
3 4 5

   (#@$(0|:],+/^:)) a    NB. parens are optional
0 1 2  3
3 4 5 12
3 5 7 15

The function is equivalent to the following (0|:],+/)^:(#@$) but uses a user-defined adverb to save parens.

Explanation for the latter code from right to left:

  • ^:(#@$)repeat ^: for the number # of dimensions $:

    • ],+/ concatenate , to the argument ] with the sum of it on the last dimension +/
    • 0|: rotate dimensions |: by putting the first one 0 to the end of the dimension-list
  • After doing the above procedure we get back the original input with sums on all dimensions.

For my older solution check revision history.

Try it online here.

\$\endgroup\$
15
\$\begingroup\$

Mathematica, 32 20 bytes

#/.List->({##,+##}&)&

Example:

In[1]:= #/.List->({##,+##}&)&[{{1, 2, 3}, {4, 5, 6}}]

Out[1]= {{1, 2, 3, 6}, {4, 5, 6, 15}, {5, 7, 9, 21}}

Explanation:

The full form of {{1, 2, 3}, {4, 5, 6}} is List[List[1, 2, 3], List[4, 5, 6]]. Then replace all the Lists in the expression with the function ({##,+##}&).

\$\endgroup\$
10
\$\begingroup\$

Python 2, 95 bytes

from numpy import*
a=copy(input())
for d in r_[:a.ndim]:a=r_[`d`,a,sum(a,d,keepdims=1)]
print a

This iterates over each dimension, concatenating its sums using NumPy.

I stumbled across NumPy's r_, which is pretty awesome for golfing. r_[:n] is shorter than range(n) and much more powerful (e.g. r_[:4, 7, 8, 10:100:10]). It can also do other things like concatenation along an arbitrary axis.

Example usage:

$ python sum.py
[[1, 2, 3], [4, 5, 6]]
[[ 1  2  3  6]
 [ 4  5  6 15]
 [ 5  7  9 21]]
\$\endgroup\$
7
\$\begingroup\$

APL, 16 15 bytes

{×≡⍵:∇¨⍵,+/⍵⋄⍵}

Thanks to @user23013 for golfing off 3 bytes and figuring out the proper input format.

Verify the test cases online with TryAPL.

Idea

The general idea is the same as in my CJam submission, for which APL allows a much shorter implementation. It consists of only two steps:

  1. Sum the array across its outmost dimension.

  2. Repeat step 1 for each subarray.

Code

{             } ⍝ Define a monadic function with argument ⍵ and reference ∇.
 ×≡⍵:           ⍝ If the depth of ⍵ is positive:
     ∇          ⍝   Apply this function...
      ¨         ⍝   to each element of...
       ⍵,       ⍝   the concatenation of ⍵...
         +/⍵    ⍝   and the sum across ⍵.
            ⋄⍵  ⍝  Else, return ⍵.
\$\endgroup\$
  • \$\begingroup\$ Just figured out the input format for your original code: ,⊂(,1)(,1)(,1)(,0) and ,⊂,⊂,⊂,¯1 respectively. So you can remove another character. \$\endgroup\$ – jimmy23013 May 22 '15 at 21:58
  • 2
    \$\begingroup\$ @user23013: So my code did work! You have to love a programming language where the input format is more difficult to get right than the actual code... \$\endgroup\$ – Dennis May 22 '15 at 23:54
6
\$\begingroup\$

Pip, 18 15 bytes

{a-a?fMaAE$+aa}

This is an anonymous function, which takes the array as an argument and returns the result. Sample invocation, using the -p flag to obtain readable output:

C:\> pip.py -pe "( {a-a?fMaAE$+aa} [[1 2 3] [4 5 6]] )"
[[1;2;3;6];[4;5;6;15];[5;7;9;21]]

The idea is basically the same as Dennis's APL, though independently derived. More specifically:

{             }  Define a lambda function with parameter a
 a-a?            Shortest way I could find to test whether the argument is a list
                 or scalar: subtracting a number from itself gives 0 (falsy);
                 subtracting a list from itself gives a list of zeros (truthy!)
     fM          If truthy, it's a list, so map the same function (f) recursively to:
       aAE         Argument, with appended element...
          $+a      ...sum of argument (fold on +)
             a   If falsy, it's a scalar, so just return it

This method works because + (along with many other operators) functions item-wise on lists in Pip--a feature inspired by array-programming languages like APL. So when you $+ a list like [[1 2 3] [4 5 6]], the result is [5 7 9] as desired. Also used in the list-or-scalar test: [1 2 3] - [1 2 3] gives [0 0 0], which is truthy (as are all lists except the empty list).

Previous 18-byte version:

{Ja=a?a(fMaAE$+a)}

Changes:

  1. Saved a byte on the scalar-or-list test--previous method was to join the argument (on empty string) and test whether equal to its un-joined self (works because [1 2 3] != 123);
  2. Eliminated the parentheses. They're necessary in the original because M is lower precedence than ? (though I'm probably going to change that, especially now): without them, the code would parse as (Ja=a?af)M(aAE$+a), leading to bizarre error messages. However, the middle argument of a ternary operator can be any expression of whatever precedence, no parentheses needed. So by making the list the truthy case, I can save those two bytes.
\$\endgroup\$
  • 2
    \$\begingroup\$ That's an interesting language you got there. Itemwise operators are what's missing in CJam and Pyth. \$\endgroup\$ – Dennis May 23 '15 at 6:15
  • \$\begingroup\$ @Dennis Thanks! It's still very much a work in progress, but there are some tasks it does quite well with. \$\endgroup\$ – DLosc May 23 '15 at 7:30
5
\$\begingroup\$

APL (25)

{N⊣{N,[⍵]←+/[⍵]N}¨⍳⍴⍴N←⍵}

APL's arrays have dimensions built-in, so this is a function that takes an n-dimensional array and then sums along each dimension.

      {N⊣{N,[⍵]←+/[⍵]N}¨⍳⍴⍴N←⍵} ↑(1 2 3)(4 5 6)
1 2 3  6
4 5 6 15
5 7 9 21

Explanation:

  • N←⍵: store the array in N.
  • ⍴⍴N: get the amount of dimensions N has. ( gives the dimensions, i.e. ⍴↑(1 2 3)(4 5 6) gives 2 3, so ⍴⍴ gives the dimensions of the dimensions.)
  • {...}¨⍳: for each number from 1 to ⍴⍴N:
    • +/[⍵]N: sum N along dimension
    • N,[⍵]←: join the result to N in that dimension
  • N: finally, return N.
\$\endgroup\$
  • \$\begingroup\$ I can't seem to make this work if the array contains singletons. How would you call this function for the third or fourth test case? \$\endgroup\$ – Dennis May 22 '15 at 20:15
  • 3
    \$\begingroup\$ @Dennis: you need to pass the function a multidimensional array. What the ↑(1 2 3)(4 5 6) is doing is simply constructing a 2-dimensional array from 2 1-dimensional ones using . It is not a built-in notation and it does not generalize the way you might think. The canonical way to construct the 3rd and 4th arrays would be 1 4 1⍴1 1 1 0 and 1 1 1 1⍴¯1, but it is also possible to construct them without referring to the sizes, e.g., the third array can also be constructed with ↑⍉⍪(,1)(,1)(,1)(,0), the fourth one can be constructed with ↑⍪⊂⍪¯1. \$\endgroup\$ – marinus May 22 '15 at 20:35
  • \$\begingroup\$ OK, that explains everything. My naïve implementation of a recursive approach works well for what I thought were arrays (e.g. f←{0=≡⍵:⍵⋄f¨⍵,+/⍵}⋄f((1 2)(3 4))((5 6)(7 8))), but it seems that nested vectors and arrays are different and the former doesn't differentiate scalars from singletons... \$\endgroup\$ – Dennis May 22 '15 at 21:12
  • 2
    \$\begingroup\$ @Dennis Golfed: {×≡⍵:∇¨⍵,+/⍵⋄⍵}((1 2)(3 4))((5 6)(7 8)). Fixed: {×⍴⍴⍵:∇↓⍵,+/⍵⋄⍵}1 4 1⍴1 1 1 0. It's shorter than Mathematica now... \$\endgroup\$ – jimmy23013 May 22 '15 at 21:40
3
\$\begingroup\$

CJam, 36 bytes

{_`{'[<}#:D{_":"D'.e]'++~a+{S}%}&}:S

This is a recursive named function that pops an array from the stack and leaves one in return.

Try the test cases in the CJam interpreter.

Idea

Sadly, CJam does not have some automagical operator that allows to add arbitrarily nested arrays, so we have to implement it ourselves. Luckily, it does that two infix operators, : (reduce) and . (vectorize), that will prove helpful for this task.

Step one is calculating the number of dimensions. This is easy: Convert the array into its string representation and count the number of leading ['s.

Now, to reduce an array of one dimension, you usually just execute :+:

[1 2] :+ e# Pushes 3.

For an array of two dimensions, + would perform concatenation instead of addition, so we have to vectorize it:

[[1 2][3 4]] :.+ Pushes [4 6].

Now, for an array of three dimensions, .+ would operate on arrays of two dimensions and perform, once again, concatenation. This time, we have to vectorize .+:

[[[1 2][3 4]][[5 6][7 8]]] :..+ e# Pushes [[[6 8] [10 12]]].

For the general case, an array of dimension D, we have to chain one :, D - 1 .'s and one +.

Of course, this only sums the array only across its outmost dimension. We can solve this by defining a function S that computes the dimension (and does nothing if it's zero), performs the sum as indicated above and, finally, applies itself to the array's elements.

Code

{                                }:S e# Define S:
 _`                                  e#   Push a string representation of a the array.
   {'[<}#                            e#   Find the index of the first non-bracket.
         :D                          e#   Save it in D.
           {                   }&    e#   If D is positive:
            _                        e#     Push a copy of the array.
             ":"D'.e]                e#     Pad ":" with "."s to a string of length D.
                     '++~            e#     Add a "+" to the string and evaluate.
                         a+          e#     Wrap the result in a array and concatenate.
                           {S}%      e#     Apply S to the elements of the array.
\$\endgroup\$
2
\$\begingroup\$

Ruby (181 139 119 108 bytes)

def d a;a.push a[0].to_s['[']?a.map{|x|d x}.transpose.map{|x|x.reduce:+}:a.reduce(:+)end
p d eval ARGF.read

Assumes input is passed as JSON.

\$\endgroup\$
  • \$\begingroup\$ And in fact you can just write a function accepting a parsed array and returns an array, and only count the 95 bytes for d in this answer. \$\endgroup\$ – jimmy23013 May 22 '15 at 14:22
2
\$\begingroup\$

Java, 669 bytes

not gonna lie, I'm quite proud of myself for this one :p

import java.lang.reflect.Array;enum S{D;<A>A s(A a){int l=Array.getLength(a),x=0;Class t=a.getClass();Class c=t.getComponentType();A r=(A)Array.newInstance(c,l+1);System.arraycopy(a,0,r,0,l);if(t==int[].class)for(;x<l;)((int[])r)[l]=((int[])r)[l]+((int[])r)[x++];else{for(;x<l;)Array.set(r,x,S.this.s(Array.get(r,x++)));Object o=Array.get(r,0);for(;--x>0;)o=s(o,Array.get(r,x));Array.set(r,l,o);}return r;}<A>A s(A a,A b){int l=Array.getLength(a),x=0;Class t=a.getClass();A r=(A)Array.newInstance(t.getComponentType(),l);if(int[].class==t)for(;x<l;)((int[])r)[x]=((int[])a)[x]+((int[])b)[x++];else for(;x<l;)Array.set(r,x,s(Array.get(a,x),Array.get(b,x++)));return r;}}

expanded with testing:

import java.lang.reflect.Array;
import java.util.Arrays;

public enum SumOf{
    Dimensions;

    <A>A sum(A array){ //call this method to solve the challenge
        int length=Array.getLength(array),x=0;
        Class arrayType=array.getClass();
        Class componentType=arrayType.getComponentType();
        //grow the array to include the sum element
        A result=(A)Array.newInstance(componentType,length+1);
        System.arraycopy(array,0,result,0,length);
        if(arrayType==int[].class) //one-dimensional array needs to be handled separately
            for(;x<length;) //find the sum
                ((int[])result)[length]=((int[])result)[length]+((int[])result)[x++];        
        else{ //multi-dimensional array
            for(;x<length;) //find the sum for each element in this dimension's array
                Array.set(result,x,sum(Array.get(result,x++)));
            //find the total sum for this dimension's array
            Object s=Array.get(result,0);
            for(;--x>0;)
                s=_sum(s,Array.get(result,x)); //add the 2 elements together
            Array.set(result,length,s);
        }
        return result;
    }

    <A>A _sum(A arrayA,A arrayB){ //this method is used by the previous method
        int length=Array.getLength(arrayA),x=0;
        Class arrayType=arrayA.getClass();
        A result=(A)Array.newInstance(arrayType.getComponentType(),length);
        if(int[].class==arrayType) //one-dimensional array needs to be handled separately
            for(;x<length;) //find the sum of both arrays
                ((int[])result)[x]=((int[])arrayA)[x]+((int[])arrayB)[x++];
        else
            for(;x<length;) //find the sum of both arrays
                Array.set(result,x,sum(Array.get(arrayA,x),Array.get(arrayB,x++)));
            return result;
        }

    static int[] intArray( int firstElement, int...array ) {
        if( array == null ) array = new int[0];
        array = Arrays.copyOf( array, array.length + 1 );
        System.arraycopy( array, 0, array, 1, array.length - 1 );
        array[0] = firstElement;
        return array;
    }

    static <E> E[] arrayArray( E firstElement, E...array ) {
        if( array == null ) array = (E[]) Array.newInstance( firstElement.getClass(), 0 );
        array = Arrays.copyOf( array, array.length + 1 );
        System.arraycopy( array, 0, array, 1, array.length - 1 );
        array[0] = firstElement;
        return array;
    }

    static void printIntArray( int[]array ){
        System.out.print("[ ");
        for( int x = 0; x < array.length; x++ )
            System.out.print( array[x] + " " );
        System.out.print("] ");
    }

    static < A > void printArray( A array ) {
        if( array.getClass() == int[].class ){
            printIntArray( (int[]) array );
        }
        else {
            System.out.print("[ ");
            int length = Array.getLength( array );
            for( int x = 0; x < length; x++ )
                printArray( Array.get( array, x ) );
            System.out.print("] ");
        }
    }

    public static void main(String[]s){
        int[] test01 = intArray( 5, 2, 3 );
        System.out.print("Input: ");
        printArray( test01 );
        System.out.print("\nOutput: ");
        printArray( SumOf.Dimensions.sum( test01 ) );
        System.out.println();

        int[][] test02 = arrayArray( intArray( 1, 2, 3 ), intArray( 4, 5, 6 ) );
        System.out.print("\nInput: ");
        printArray( test02 );
        System.out.print("\nOutput: ");
        printArray( SumOf.Dimensions.sum( test02 ) );
        System.out.println();

        int[][][] test03 = arrayArray( arrayArray( intArray( 1 ), intArray( 1 ), intArray( 1 ), intArray( 0 ) ) );
        System.out.print("\nInput: ");
        printArray( test03 );
        System.out.print("\nOutput: ");
        printArray( SumOf.Dimensions.sum( test03 ) );
        System.out.println();

        int[][][][] test04 = arrayArray( arrayArray( arrayArray( intArray( -1 ) ) ) );
        System.out.print("\nInput: ");
        printArray( test04 );
        System.out.print("\nOutput: ");
        printArray( SumOf.Dimensions.sum( test04 ) );
        System.out.println();

        int[][][] test05 = arrayArray( arrayArray( intArray( 1, 2, 3 ), intArray( 4, 5, 6 ), intArray( 7, 8, 9 ) ), arrayArray( intArray( 11, 12, 13 ), intArray( 14, 15, 16 ), intArray( 17, 18, 19 ) ), arrayArray( intArray( 21, 22, 23 ), intArray( 24, 25, 26 ), intArray( 27, 28, 29 ) ) );
        System.out.print("\nInput: ");
        printArray( test05 );
        System.out.print("\nOutput: ");
        printArray( SumOf.Dimensions.sum( test05 ) );
        System.out.println();
    }

}

running the expanded testing version prints this:

Input: [ 5 2 3 ] 
Output: [ 5 2 3 10 ] 

Input: [ [ 1 2 3 ] [ 4 5 6 ] ] 
Output: [ [ 1 2 3 6 ] [ 4 5 6 15 ] [ 5 7 9 21 ] ] 

Input: [ [ [ 1 ] [ 1 ] [ 1 ] [ 0 ] ] ] 
Output: [ [ [ 1 1 ] [ 1 1 ] [ 1 1 ] [ 0 0 ] [ 3 3 ] ] [ [ 1 1 ] [ 1 1 ] [ 1 1 ] [ 0 0 ] [ 3 3 ] ] ] 

Input: [ [ [ [ -1 ] ] ] ] 
Output: [ [ [ [ -1 -1 ] [ -1 -1 ] ] [ [ -1 -1 ] [ -1 -1 ] ] ] [ [ [ -1 -1 ] [ -1 -1 ] ] [ [ -1 -1 ] [ -1 -1 ] ] ] ] 

Input: [ [ [ 1 2 3 ] [ 4 5 6 ] [ 7 8 9 ] ] [ [ 11 12 13 ] [ 14 15 16 ] [ 17 18 19 ] ] [ [ 21 22 23 ] [ 24 25 26 ] [ 27 28 29 ] ] ] 
Output: [ [ [ 1 2 3 6 ] [ 4 5 6 15 ] [ 7 8 9 24 ] [ 12 15 18 45 ] ] [ [ 11 12 13 36 ] [ 14 15 16 45 ] [ 17 18 19 54 ] [ 42 45 48 135 ] ] [ [ 21 22 23 66 ] [ 24 25 26 75 ] [ 27 28 29 84 ] [ 72 75 78 225 ] ] [ [ 33 36 39 108 ] [ 42 45 48 135 ] [ 51 54 57 162 ] [ 126 135 144 405 ] ] ] 
\$\endgroup\$
  • \$\begingroup\$ erm for the expanded version, the line: Array.set(result,x,sum(Array.get(arrayA,x),Array.get(arrayB,x++))); in the _sum(...) method should have called _sum(...), not sum(...). my bad \$\endgroup\$ – Jack Ammo May 24 '15 at 6:14

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.