Array alignment addition

39

1

Introduction

Consider two non-empty integer arrays, say A = [0 3 2 2 8 4] and B = [7 8 7 2]. To perform alignment addition on them, we do the following:

  1. Repeat each array enough times to have total length lcm(length(A), length(B)). Here lcm stands for lowest common multiple.

    A -> [0 3 2 2  8 4][0 3  2 2 8 4]
    B -> [7 8 7 2][7 8  7 2][7 8 7 2]
    
  2. Perform element-wise addition on the repeated arrays, and cut the result at every position where there's a cut in either of them.

    A -> [0  3 2 2   8  4][0 3  2  2  8 4]
    B -> [7  8 7 2][ 7  8  7 2][7  8  7 2]
      -> [7 11 9 4][15 12][7 5][9 10 15 6]
    
  3. This array of arrays is your result.

The task

Your inputs are two non-empty arrays of integers, and your output shall be the result of their alignment addition, as defined above. The inputs and output can be in any reasonable format. You don't have to worry about integer overflow when performing the addition.

Rules and scoring

You can write a full program or a function. The lowest byte count wins.

Test cases

[1] [4] -> [[5]]
[1,2,-3,-4] [15] -> [[16],[17],[12],[11]]
[0,-4] [2,1,0,-3] -> [[2,-3],[0,-7]]
[0,3,2,2,8,4] [7,8,7,2] -> [[7,11,9,4],[15,12],[7,5],[9,10,15,6]]
[18,17,16] [-1,-2,-3,-4] -> [[17,15,13],[14],[16,14],[15,13],[15],[16,14,12]]
[18,17,16,15] [-1,-2,-3,-4] -> [[17,15,13,11]]
[1,1,1,1,1] [6,5,6,5,6,5,6,2,1] -> [[7,6,7,6,7],[6,7,3,2],[7],[6,7,6,7,6],[7,3,2],[7,6],[7,6,7,6,7],[3,2],[7,6,7],[6,7,6,7,3],[2],[7,6,7,6],[7,6,7,3,2]]
[1,1,1,1,1,1] [6,5,6,5,6,5,6,2,1] -> [[7,6,7,6,7,6],[7,3,2],[7,6,7],[6,7,6,7,3,2]]
[1,1,1,1,1,1,1] [6,5,6,5,6,5,6,2,1] -> [[7,6,7,6,7,6,7],[3,2],[7,6,7,6,7],[6,7,3,2],[7,6,7],[6,7,6,7,3,2],[7],[6,7,6,7,6,7,3],[2],[7,6,7,6,7,6],[7,3,2],[7,6,7,6],[7,6,7,3,2],[7,6],[7,6,7,6,7,3,2]]

Zgarb

Posted 2016-12-16T07:08:37.067

Reputation: 39 083

C doesn't have a way to know an array's length -- can I request the length of the array as an argument, or have it stored at the beginning of the array? – cat – 2016-12-17T16:47:53.457

1@cat You can take the lengths as extra arguments, if there's no other way of getting them. – Zgarb – 2016-12-17T17:11:10.127

Answers

9

JavaScript (ES6), 101 99 bytes

Takes input as 2 arrays. Returns a string.

f=(a,b,j=0,s='')=>a.map((v,i)=>(s+=i*j?' ':s&&'][',s+=b[j]+v,j=++j%b.length))|j?f(a,b,j,s):`[${s}]`

How it works

We iterate on the first array a with a pointer i while updating another pointer j into the second array b. The sums a[i] + b[j] are appended to the output string s. A separator is inserted each time i == 0 or j == 0. We repeat this process until j is back exactly at the beginning of b at the end of an iteration.

Note: When the | operator is applied, a.map(...) is coerced to either NaN (if a contains more than one element) or the current value of j (if a contains exactly one element). Therefore, a.map(...)|j == j in all cases and is safe to use here.

Test cases

f=(a,b,j=0,s='')=>a.map((v,i)=>(s+=i*j?' ':s&&'][',s+=b[j]+v,j=++j%b.length))|j?f(a,b,j,s):`[${s}]`

console.log(f([1], [4]));
console.log(f([1,2,-3,-4], [15]));
console.log(f([0,-4], [2,1,0,-3]));
console.log(f([0,3,2,2,8,4], [7,8,7,2]));
console.log(f([18,17,16], [-1,-2,-3,-4]));
console.log(f([18,17,16,15], [-1,-2,-3,-4]));
console.log(f([1,1,1,1,1], [6,5,6,5,6,5,6,2,1]));
console.log(f([1,1,1,1,1,1], [6,5,6,5,6,5,6,2,1]));
console.log(f([1,1,1,1,1,1,1], [6,5,6,5,6,5,6,2,1]));

Arnauld

Posted 2016-12-16T07:08:37.067

Reputation: 111 334

I have not even tried to understand the answer, +1 for the note. I'll copy and keep it to paste when needed – edc65 – 2016-12-17T09:18:58.423

6

Haskell, 84 79 bytes

a#b=a%b where(c:d)%(e:f)|(x:y)<-d%f=(c+e:x):y;[]%[]=[[]];c%[]=[]:c%b;_%d=[]:a%d

My first version was the same in more readable layout:

a#b=a%b where
 (c:d)%(e:f)|(x:y)<-d%f=(c+e:x):y
 []%[]=[[]]
 c%[]=[]:c%b
 _%d=[]:a%d

Using a local definition to avoid having to give (%) extra arguments for a and b. Amazingly, this is almost the same solution given at almost the same time as @nimi's, from whom I took the idea of using only one line for the local definition.

Usage:

*Main> [0,3,2,2,8,4] # [7,8,7,2]
[[7,11,9,4],[15,12],[7,5],[9,10,15,6]]

Christian Sievers

Posted 2016-12-16T07:08:37.067

Reputation: 6 366

Oh, that's a nice way to prepend the sum to the first element of the list. Far shorter than my cumbersome !. – nimi – 2016-12-16T19:39:27.853

4

PHP, 126 120 bytes

function($a,$b){do{$c[$j][]=$a[$i%$x=count($a)]+$b[$i%$y=count($b)];++$i%$x&&$i%$y?:$j++;}while($i%$x|$i%$y);return$c;};

Try it here!

Anonymous function that returns the resulting array of arrays.

Essentially, we loop through the contents of both of our arrays, modding our iterator by the length of the array to simulate 'copying' them. Taking each of the values from the arrays, we sum them and add them to an array in $c. If we reach the end of one of our input arrays (a split, in terms of the challenge), we start assigning into a new array in $c.

The reason for the do while loop is because our condition is based on $i, which starts at 0. If we use a loop where the condition is checked at the beginning, the loop wouldn't run

We only end the summation once we reach the end of both of the arrays at the same time, which would imply the LCM.

Xanderhall

Posted 2016-12-16T07:08:37.067

Reputation: 1 236

Shouldn´t that be $b[$i%$y]? You can save 3 bytes by moving $x=count($a) to the first usage of $x; same for $y=count($b) and one byte with bitwise or in the while condition – Titus – 2016-12-16T16:30:21.387

But I think anonymous functions are considered snippets and hence are no valid answers. – Titus – 2016-12-16T17:10:30.300

@Titus Anonymous functions are allowed by default as per consensus on Meta.

– Zgarb – 2016-12-16T18:53:35.957

Thanks for the suggestions @Titus, I just kinda threw this together cause I wanted to beat the other PHP answers :P – Xanderhall – 2016-12-16T19:22:53.380

4

Haskell, 87 84 bytes

a#b=a%b where[]%[]=[[]];(e:f)%(g:h)=f%h!(e+g);e%[]=[]:e%b;_%g=[]:a%g
(m:n)!l=(l:m):n

Usage example: [0,3,2,2,8,4] # [7,8,7,2] -> [[7,11,9,4],[15,12],[7,5],[9,10,15,6]].

Simple recursion. Base case: both lists are empty. If only one of them is empty, restart with a full version and start a new cluster in the output. If none is empty, prepend the sum to the from element.

Have also a look at @Christian Sievers' answer, which is almost identical and was posted a few seconds earlier.

nimi

Posted 2016-12-16T07:08:37.067

Reputation: 34 639

Are you sure? Is there a way to get the exact times? – Christian Sievers – 2016-12-16T21:36:36.520

@ChristianSievers: I don't know if you can see the times directly. When the times of our edits were shown in minutes, I remember that yours was counted up a few seconds (about 20) earlier than mine. – nimi – 2016-12-16T22:27:55.413

You're right: I found timestamps in the html source code of this page – Christian Sievers – 2016-12-16T23:41:42.467

Hover over the time in "answered 2 days ago" to see the exact time. (Hint: this is a standard UI across the internet, so (a) if you want an exact time, try hovering the relative time, and (b) if you ever implement something that shows relative time, please show the exact time on hover!) – wchargin – 2016-12-18T18:28:25.637

2

J, 34 32 bytes

[:(<;.1~*)/[:+/*.&#$&>,:&(;2>#\)

Try it online!

Explanation

[:(<;.1~*)/[:+/*.&#$&>,:&(;2>#\)  Input: array A (LHS), array B (RHS)
                             #\   Length of each prefix of A and B
                           2>     Less than 2
                          ;       Link each with A and B
                      ,:&         Pair them
                  #               Length of A and B
               *.&                LCM of the lengths
                    &>            For each box
                   $              Reshape it to the LCM of the lengths
           [:+/                   Reduce by addition
[:        /                       Reduce by
        *                           Sign of RHS
   <;.1~                            Box each partition of LHS

miles

Posted 2016-12-16T07:08:37.067

Reputation: 15 654

2

Python 3.5 - (146137134130+12) = 142 Bytes

import math
def s(a,b):
 l,k,*r=map(len,[a,b])
 for i in range(l*k//math.gcd(l,k)):
  r+=a[i%l]+b[i%k],
  if i%k==k-1or i%l==l-1:print(r);r=[]

I cannot figure out how to put the whole for loop in one line.

Edits:

Gurupad Mamadapur

Posted 2016-12-16T07:08:37.067

Reputation: 1 791

This gives an error for me. The gcd function is in fractions, not math. – Zgarb – 2016-12-16T11:10:25.367

@Zgarb the gcd in fractions module is deprecated, you can check the change here . I guess rexter is using the old version 3.4.3.

– Gurupad Mamadapur – 2016-12-16T11:30:42.703

Neat, I didn't know about this change. You should mark the language as "Python 3.5" though, since it doesn't work in 3.4 or earlier. Also, you can drop the parentheses around l*k and have print(r);r=[] on the last line. – Zgarb – 2016-12-16T11:30:53.000

Are you sure your byte count is correct? I think there're only 145 bytes. – vaultah – 2016-12-16T12:42:32.423

In any case, you can save some more bytes: 1) l,k,*r=map(len,[a,b]) 2) r+=a[i%l]+b[i%k], 3) if i%k==k-1or i%l==l-1:... – vaultah – 2016-12-16T12:46:24.300

@vaultah Yes, the byte count is correct. And r+=[....] is needed. Thanks for other suggestions. – Gurupad Mamadapur – 2016-12-16T12:59:32.700

@GurupadMamadapur you don't need square brackets if you add a comma in the end. – vaultah – 2016-12-16T13:00:50.197

@vaultah Whoa, I didn't see that comma. – Gurupad Mamadapur – 2016-12-16T13:05:23.657

1I'm getting 142 bytes. Are you using Windows? Windows usually counts newlines as 2 bytes each, but here each newline is counted as a single byte. – mathmandan – 2016-12-17T03:23:28.267

@mathmandan Thanks for saving lots of bytes in every answer of mine :D – Gurupad Mamadapur – 2016-12-17T07:42:12.617

2

Python 2, 119 bytes

a=input()
i,v,l=0,list(a),len
while 1:q=l(v[0])>l(v[1]);print map(sum,zip(*v)[i:]);i=l(v[q]);v[q]+=a[q];1/(i-l(v[q^1]))

Takes input from stdin as two tuples separated by comma, outputs resulting lists to stdout. Terminates by raising the ZeroDivisionError exception, since that seems to be allowed.

For example, if the input is (0, 3, 2, 2, 8, 4), (7, 8, 7, 2), the program will print

[7, 11, 9, 4]
[15, 12]
[7, 5]
[9, 10, 15, 6]

to stdout and the exception traceback to stderr.

vaultah

Posted 2016-12-16T07:08:37.067

Reputation: 1 254

You can exit the program by throwing an error. Then you might be able to get the loop into a single line. – Zgarb – 2016-12-16T14:28:25.597

2

Octave , 113 bytes

@(a,b)mat2cell(sum([repmat(a,1,(L=lcm(A=numel(a),B=numel(b)))/A);repmat(b,1,L/B)]),1,diff(unique([0:A:L,0:B:L])))

this function is directly callable to call it place it in parenthesis and call as (@(a,b)...)([1 2 3 4],[6 4 5])

rahnema1

Posted 2016-12-16T07:08:37.067

Reputation: 5 435

1

Now TIO-Nexus supports Octave. Here's a link to test the code

– Luis Mendo – 2016-12-16T18:28:59.157

@LuisMendo Thanks, interesting service – rahnema1 – 2016-12-16T18:32:53.173

2

CJam, 30 bytes

{Sf*Laf+_s,f*:.+La/0=S2*a-Sa/}

Try it online!

Takes input as a pair of lists.

Explanation

The idea is to insert some markers into the input arrays (in the form of short strings) which indicate where the aligned array ends, and where we need to insert the breaks in the arrays. This way we can avoid having to compute the LCM.

Sf*    e# Riffle each list with spaces. These are just place holders, so that having
       e# an array-end marker between two elements doesn't misalign subsequent elements.
Laf+   e# Append an empty string to each list. This is the array-end marker.
_s,    e# Convert the pair of lists to a string and get its length. This is always
       e# greater than the number of elements in either input.
f*     e# Repeat either array that many times. This is definitely more than necessary
       e# to reach the LCM (since multiplying by the length of the other list always
       e# gives a common multiple).
:.+    e# Pairwise addition of the list elements. There are four cases:
       e# - Both elements are numbers, add them. This is the actual addition
       e#   we need for the problem.
       e# - Both elements are spaces. This is just a regular position between
       e#   list elements.
       e# - One is a space, one is empty: the result is a single space, and
       e#   this marks a position where one of the arrays ended, which means
       e#   we need to split here.
       e# - Both elements are empty. This happens at the LCM of both list lengths
       e#   and indicates where we need to stop the output.
La/0=  e# Split the input around empty strings and discard everything except
       e# the first chunk.
S2*a-  e# Remove the double-space strings, we no longer need them.
Sa/    e# Split the list around single spaces.

Martin Ender

Posted 2016-12-16T07:08:37.067

Reputation: 184 808

2

Jelly, 21 20 18 bytes

ṁ€L€æl/$S
J€ỊÇœṗÇḊ

Try it online!

How it works

ṁ€L€æl/$S  Helper link. Argument [X, Y] (arrays of integers).

       $   Combine the two links to the left into a monadic chain.
  L€       Length each; yield the lengths of X and Y.
    æl/    Reduce by least common multiple.
ṁ€         Mold each; cyclically repeat the elements of X and Y to extend them
           to length lcm(length(X), length(Y)).
        S  Compute the sum of the extended X and Y arrays.

J€ỊÇœṗÇḊ   Main link. Argument [A, B] (arrays of integers).

J€         Indices each; replace A and B by the arrays of there 1-based indices.
  Ị        Insignificant; map 1 to itself, all other indices to 0.
   Ç       Apply the helper link to the result.
           This yield a Boolean array with a 1 (or 2) at all indices where a new
           repetition of A or B (or both) begins.
      Ç    Apply the helper link to [A, B].
    œṗ     Partition; break the result to the right at truthy elements (1 or 2) in
           the result to the right.
       Ḋ   Dequeue; remove the first element of the partition (empty array).

Dennis

Posted 2016-12-16T07:08:37.067

Reputation: 196 637

1

Haskell, 166 bytes

This is probably not the most elegant approach: Basically the function ? creates one list of the needed length with thesums, and % is cutting this sum up again. ! is the final function that merges those two.

l=length
a?b=take(lcm(l a)$l b)$zipWith(+)(cycle a)$cycle b
l%(i:ind)|l==[]=[]|1>0=take i l:(drop i l)%(map(+(-i))ind)
a!b=(a?b)%[k|k<-[1..],k`mod`l a<1||k`mod`l b<1]

flawr

Posted 2016-12-16T07:08:37.067

Reputation: 40 560

You can replace ind by k or something, and there are some unnecessary parentheses around drop i l and map(+(-i))ind. Consider also having two cases for %, with pattern matching on l. – Zgarb – 2016-12-16T11:33:02.973

1

[PHP], 183 152 135 bytes

function O($A,$B){while($f<2){$O[$k][]=$A[+$i]+$B[+$j];$f=0;isset($A[++$i])?:$i=!++$k|!++$f;isset($B[++$j])?:$j=!++$k|!++$f;}return$O;}

Nice version:

function O($A,$B)
{
    while($f<2) {
        $O[$k][]=$A[+$i]+$B[+$j];
        $f=0;
        isset($A[++$i])?:$i=!++$k|!++$f;
        isset($B[++$j])?:$j=!++$k|!++$f;
    }

    return$O;
}

Output:

array (size=4)
  0 => 
    array (size=4)
      0 => int 7
      1 => int 11
      2 => int 9
      3 => int 4
  1 => 
    array (size=2)
      0 => int 15
      1 => int 12
  2 => 
    array (size=2)
      0 => int 7
      1 => int 5
  3 => 
    array (size=4)
      0 => int 9
      1 => int 10
      2 => int 15
      3 => int 6

Dexa

Posted 2016-12-16T07:08:37.067

Reputation: 236

Draw even with me using these tweaks: $i=$j=$k=0; is unnecessary if you use +$i etc. for the array indexes in the appending assignment (-8 bytes). $i++;if(!isset($A[$i])){$i=0;$k++;} --> isset($A[++$i])?:$i=!++$k; (-9, twice). $i==0&&$j==0&&!isset() --> !$i&!$j&!isset() (-6). return$O; needs no space (-1). – Titus – 2016-12-16T15:28:49.260

@Titus can't remove $i=$j=0; part since first values from arrays won't be correct. I've modified logic a little so not sure how to implement ternary operators in this case. Thanks for ++$i advices. – Dexa – 2016-12-16T16:18:22.333

Try unset($i);$A[+$i]. The + will cast null to integer 0. – Titus – 2016-12-16T16:26:37.697

if(!isset($A[++$i])){$i=0;++$k;++$f;} --> isset($A[++$i])?:$i=!++$k|!++$f; still saves 5 bytes each. Save one more with $f<2 instead of $f!=2. and another two with while($f=$f<3){...} instead of while($f<2){$f=0;...} (initializes and resets $f to 1 unless it´s incremented twice) – Titus – 2016-12-16T16:39:36.723

@Titus Thanks a lot, it is shorter now. – Dexa – 2016-12-16T16:52:04.313

Oh and I think with while(!$k|$i|$j) you can remove $f again. (That should get you down to 125 bytes). – Titus – 2016-12-16T17:03:18.633

1

PHP, 150 121 119 bytes

function($a,$b){while($i<2|$x|$y)$r[$k+=!($x=$i%count($a))|!$y=$i++%count($b)][]=$a[$x]+$b[$y];array_pop($r);return$r;}

anonymous function takes input as arrays.

breakdown

while($i<2|$x|$y)   // loop while either $a or $b has NO cut
    $r[
                // if either $a or $b has a cut, increment $k; post-increment $i
        $k+=!($x=$i%count($a))|!$y=$i++%count($b)
                // append current $a + current $b to $r[$k]
    ][]=$a[$x]+$b[$y];
array_pop($r);  // $r has one element too much; remove it
return$r;

Titus

Posted 2016-12-16T07:08:37.067

Reputation: 13 814

1

Python 3.5, 210 176 173 169 158 Bytes

def f(a,b):
 x=[];e=f=0              
 while 1:
  if e==len(a):         
   print(x);x=[];e=0;
   if f==len(b):break
  if f==len(b):print(x);x=[];f=0
 x+=a[e]+b[f],;e+=1;f+=1

Takes two lists as input and prints all the lists.

Its my first answer and I don't know how to golf yet. The basic idea I've used is to have two counters for each list which indicate a split and a current list where the added values are appended onto; as soon as a split is encountered, we print the current list and make a new empty one.

  • Saved 34 bytes: Thanks to Dennis and TimmyD
  • Saved 3 bytes: was using c and d for len(a) and len(b), but turns out they weren't useful
  • Saved 4 bytes: Thanks to orlp, removed unwanted paranthesis
  • Saved 11 bytes: rearranged some blocks and crunched them down

officialaimm

Posted 2016-12-16T07:08:37.067

Reputation: 2 739

1Hi, and welcome to Programming Puzzles & Code Golf! Non-competing means something else here; you should remove that. You can save quite a few bytes by eliminating whitespace. For example, lines 2 to 5 can become x=[];c=len(a);d=len(b);e=f=0. Also, true can become 1, and x.append(a[e]+b[f]) can become x+=a[e]+b[f],. – Dennis – 2016-12-16T16:40:17.367

1

Welcome to PPCG! In addition to Dennis' specific tweaks, check out Tips for Golfing in Python to get some more general hints and tricks.

– AdmBorkBork – 2016-12-16T16:58:19.223

1if and while statements do not need parenthesis. – orlp – 2016-12-16T23:10:48.323

1

PowerShell, 147 145 bytes

param($a,$b)$o=@{};do{$o[+$j]+=,($a[+$i%($x=$a.count)]+$b[$i++%($y=$b.count)]);if(!($i%$x-and$i%$y)){$j++}}until(($x,$y|?{!($i%$_)}).count-eq2)$o

Try it online!

(Golfing suggestions welcome. I feel there's probably another 10 to 15 bytes that can be squeezed out of this.)

Takes input as two explicit arrays (with the @(...) syntax) as command-line arguments. Returns a hashtable of the resulting arrays, because multidimensional arrays in PowerShell can get weird, and this is more consistent. Sets some initial variables, then enters a do/until loop again, with the conditional being until $i is the lcm of the array counts.

Each loop iteration, we add the corresponding $a and $b values together, treat it as an array ,(...) before adding it into the hashtable $o at the appropriate spot $j. The array encapsulation is necessary to prevent arithmetical addition -- this forces the += to overload to array concatenation instead. Then, a conditional on $x and $y (the counts) to determine if we're at an array edge - if so, we increment $j.

Finally, we leave $o on the pipeline and output is implicit.
(NB: Due to how PowerShell enumerates hashtables with the default Write-Output, this tends to be output "backward"; as in, the "0th" resultant array is on the "bottom" of the output. The hash itself is fine, and would be used just fine if you e.g., encapsulated this code in a return variable ... it just looks odd when it's printed.)

Saved 2 bytes by moving $x and $y into the array indexing rather than separate (saved two semicolons).

AdmBorkBork

Posted 2016-12-16T07:08:37.067

Reputation: 41 581

1

Python 2, 113 bytes

a,b=input()
i=m=n=0;r=[]
while(not i)+m+n:r+=[[]]*(not m*n);r[-1]+=[a[m]+b[n]];i+=1;m=i%len(a);n=i%len(b)
print r

orlp

Posted 2016-12-16T07:08:37.067

Reputation: 37 067

Could the nots be <1s instead? – Zgarb – 2016-12-17T10:15:10.923

1

Racket 373 bytes

(let*((lg length)(fl flatten)(ml make-list)(t rest)(r reverse)(m modulo)(o cons)(ln(lg l))(jn(lg j))(c(lcm ln jn))(l2(fl(ml(/ c ln)l)))
(j2(fl(ml(/ c jn)j)))(ll(for/list((a l2)(b j2))(+ a b))))(let p((ll ll)(ol '())(tl '())(n 0))(cond[(empty? ll)(t(r(o(r tl)ol)))]
[(or(= 0(m n ln))(= 0(m n jn)))(p(t ll)(o(r tl)ol)(take ll 1)(+ 1 n))][(p(t ll)ol(o(first ll)tl)(+ 1 n))])))

Ungolfed:

(define(f l j)
  (let* ((ln (length l))
         (jn (length j))
         (c (lcm ln jn))
         (l2 (flatten (make-list (/ c ln) l)))
         (j2 (flatten (make-list (/ c jn) j)))
         (ll (for/list ((a l2)(b j2))
               (+ a b))))

    ; TO CUT LIST INTO PARTS: 
    (let loop ((ll ll)
               (ol '())
               (templ '())
               (n 0))
      (cond
        [(empty? ll) 
         (rest (reverse (cons (reverse templ) ol)))]
        [(or (= 0 (modulo n ln))
             (= 0 (modulo n jn)))
         (loop (rest ll)
               (cons (reverse templ) ol)
               (list (first ll))
               (add1 n))]
        [(loop (rest ll)
               ol
               (cons (first ll) templ)
               (add1 n))]))))

Testing:

(f '[1]  '[4])
(f '[1 2 -3 -4] '[15])
(f '[0 3 2 2 8 4]  '[7 8 7 2])

Output:

'((5))
'((16) (17) (12) (11))
'((7 11 9 4) (15 12) (7 5) (9 10 15 6))

rnso

Posted 2016-12-16T07:08:37.067

Reputation: 1 635

1

Clojure, 280 206 bytes

(fn[a b](let[A(count a)B(count b)Q quot](map #(map last %)(partition-by first(take-while #((% 0)2)(map-indexed(fn[i s][[(Q i A)(Q i B)(or(= i 0)(>(mod i A)0)(>(mod i B)0))]s])(map +(cycle a)(cycle b))))))))

Well this makes a lot more sense. Generating the element-wise sum, adding positional metadata, taking while we haven't repeated yet and putting the sum value to each partition.

(def f (fn[a b]
         (let[A(count a)B(count b)Q quot]
           (->> (map +(cycle a)(cycle b))
                (map-indexed (fn [i s][[(Q i A)(Q i B)(or(= i 0)(>(mod i A)0)(>(mod i B)0))]s]))
                (take-while #((% 0)2))
                (partition-by first)
                (map #(map last %))))))

Original: I'm hoping to improve this but this is the sortest one I have for now.

(fn[a b](let [C cycle o count c(take-while #(or(=(% 0)0)(>(% 1)0)(>(% 2)0))(map-indexed(fn[i[A B]][i(mod i(o a))(mod i(o b))(+ A B)])(map(fn[& v]v)(C a)(C b))))](map #(map last %)(partition-by first(map(fn[p c][p(last c)])(reductions + (map #(if(or(=(% 1)0)(=(% 2)0))1 0)c))c)))))

Ungolfed and verbose:

(def f (fn[a b]
         (let [c(->> (map (fn[& v]v) (cycle a) (cycle b))
                     (map-indexed (fn[i[A B]][i (mod i(count a)) (mod i(count b)) (+ A B)]))
                     (take-while #(or(=(% 0)0)(>(% 1)0)(>(% 2)0))))]
           (->> (map (fn[p c][p(last c)]) (reductions +(map #(if(or(=(% 1)0)(=(% 2)0))1 0)c)) c)
                (partition-by first)
                (map #(map last %))))))

Starts by "merging" an infinite cycle of collections a and b, adds metadata on each element's index within the collection, takes until both sequences start from index 0 again.

This collection c is then merged with partition data (a cumulative sum of ones and zeroes), partitioned and the last element (being sum of items) is selected.

I think for significant improvements a totally different approach is required.

NikoNyrh

Posted 2016-12-16T07:08:37.067

Reputation: 2 361

0

C++14, 206 bytes

As unnamed generic lambda, requiring input containers P,Q and output container R to be like vector<vector<int>>.

[](auto P,auto Q,auto&R){R.clear();auto a=P.begin(),b=Q.begin(),x=P.end(),y=Q.end();auto A=a,B=b;do{R.emplace_back();while(a!=x&&b!=y)R.back().push_back(*a+++*b++);a=a==x?A:a;b=b==y?B:b;}while(a!=A||b!=B);}

Ungolfed and usage:

#include<vector>
#include<iostream>

using namespace std;

auto f=
[](auto P,auto Q,auto&R){
 R.clear();               //just clear the output to be sure
 //a and b are the iterators, x and y is the end
 auto a=P.begin(),b=Q.begin(),x=P.end(),y=Q.end();
 //just some abbreviations for .begin()
 auto A=a,B=b;
 do{
  R.emplace_back();      //add new vector
  while(a!=x&&b!=y)      //while not at the end of one vector
   R.back().push_back(*a+++*b++);  //add the pointed elements and advance
  a=a==x?A:a;            //reset if at the end   
  b=b==y?B:b;
 }while(a!=A||b!=B);     //if both were resetted, then finish
}
;


int main(){
 vector<int> A = {0, 3, 2, 2, 8, 4};
 vector<int> B = {7, 8, 7, 2};
 vector<vector<int>> R;
 f(A,B,R);
 for (auto c:R){
  for (int x:c)
   cout << x << ", ";
  cout << endl;
 }
 cout << endl;
}

Karl Napf

Posted 2016-12-16T07:08:37.067

Reputation: 4 131

0

Mathematica 112 Bytes

This could probably be improved upon. The idea is to create a 2D array with the second element used to track the lessor of the counter i mod the length of each input array.

Split[Table[{#[[1,(m=Mod[i,d=Length/@#,1])[[1]]]]+#[[2,m[[2]]]],Min@m},{i,LCM@@d}],#2[[2]]>#1[[2]]&][[;;,;;,1]]&

Usage

%@{{0,3,2,2,8,4},{7,8,7,2}}

Kelly Lowder

Posted 2016-12-16T07:08:37.067

Reputation: 3 225

0

JavaScript (ES6), 131 bytes

(a,b,g=(r,[n,...d]=a,[m,...e]=b,s=[])=>1/n?1/m?g(r,d,e,[...s,n+m]):g([...r,s],[n,...d]):1/m?g([...r,s],a,[m,...e]):[...r,s])=>g([])

Slightly ungolfed:

(a,b,r=[],[n,...d]=a,[m,...e]=b,s=[])
=>1/n?1/m?f(a,b,r,d,e,[...s,n+m])
         :f(a,b,[...r,s],[n,...d],b,[])
     :1/m?f(a,b,[...r,s],a,[m,...e],[])
         :[...r,s]
  • If both arrays d and e contain numbers, the sum of the first number is appended to s and the remaining elements are processed recursively
  • If one of the arrays contains numbers, the array of sums s is appended to the result r and the other array is reset to its initial array
  • If both arrays are empty then simply return the result with the last sums appended.

Sadly this solution doesn't have the ruthless efficiency of @Arnauld's, but at least I think it's a beautiful solution.

Neil

Posted 2016-12-16T07:08:37.067

Reputation: 95 035