39
\$\begingroup\$

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 \$\text{lcm(length(A), length(B))}\$. Here \$\text{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]]
\$\endgroup\$
2
  • \$\begingroup\$ 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? \$\endgroup\$
    – cat
    Commented Dec 17, 2016 at 16:47
  • 2
    \$\begingroup\$ @cat You can take the lengths as extra arguments, if there's no other way of getting them. \$\endgroup\$
    – Zgarb
    Commented Dec 17, 2016 at 17:11

22 Answers 22

9
\$\begingroup\$

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]));

\$\endgroup\$
1
  • \$\begingroup\$ I have not even tried to understand the answer, +1 for the note. I'll copy and keep it to paste when needed \$\endgroup\$
    – edc65
    Commented Dec 17, 2016 at 9:18
6
\$\begingroup\$

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]]
\$\endgroup\$
1
  • \$\begingroup\$ Oh, that's a nice way to prepend the sum to the first element of the list. Far shorter than my cumbersome !. \$\endgroup\$
    – nimi
    Commented Dec 16, 2016 at 19:39
4
\$\begingroup\$

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.

\$\endgroup\$
4
  • \$\begingroup\$ 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 \$\endgroup\$
    – Titus
    Commented Dec 16, 2016 at 16:30
  • \$\begingroup\$ But I think anonymous functions are considered snippets and hence are no valid answers. \$\endgroup\$
    – Titus
    Commented Dec 16, 2016 at 17:10
  • \$\begingroup\$ @Titus Anonymous functions are allowed by default as per consensus on Meta. \$\endgroup\$
    – Zgarb
    Commented Dec 16, 2016 at 18:53
  • \$\begingroup\$ Thanks for the suggestions @Titus, I just kinda threw this together cause I wanted to beat the other PHP answers :P \$\endgroup\$
    – Xanderhall
    Commented Dec 16, 2016 at 19:22
4
\$\begingroup\$

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.

\$\endgroup\$
4
  • \$\begingroup\$ Are you sure? Is there a way to get the exact times? \$\endgroup\$ Commented Dec 16, 2016 at 21:36
  • \$\begingroup\$ @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. \$\endgroup\$
    – nimi
    Commented Dec 16, 2016 at 22:27
  • \$\begingroup\$ You're right: I found timestamps in the html source code of this page \$\endgroup\$ Commented Dec 16, 2016 at 23:41
  • \$\begingroup\$ 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!) \$\endgroup\$
    – wchargin
    Commented Dec 18, 2016 at 18:28
2
\$\begingroup\$

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])

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Now TIO-Nexus supports Octave. Here's a link to test the code \$\endgroup\$
    – Luis Mendo
    Commented Dec 16, 2016 at 18:28
  • \$\begingroup\$ @LuisMendo Thanks, interesting service \$\endgroup\$
    – rahnema1
    Commented Dec 16, 2016 at 18:32
2
\$\begingroup\$

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.
\$\endgroup\$
2
\$\begingroup\$

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).
\$\endgroup\$
2
\$\begingroup\$

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:

\$\endgroup\$
10
  • \$\begingroup\$ This gives an error for me. The gcd function is in fractions, not math. \$\endgroup\$
    – Zgarb
    Commented Dec 16, 2016 at 11:10
  • \$\begingroup\$ @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. \$\endgroup\$ Commented Dec 16, 2016 at 11:30
  • \$\begingroup\$ 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. \$\endgroup\$
    – Zgarb
    Commented Dec 16, 2016 at 11:30
  • \$\begingroup\$ Are you sure your byte count is correct? I think there're only 145 bytes. \$\endgroup\$
    – vaultah
    Commented Dec 16, 2016 at 12:42
  • 1
    \$\begingroup\$ I'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. \$\endgroup\$
    – mathmandan
    Commented Dec 17, 2016 at 3:23
2
\$\begingroup\$

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.

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

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
\$\endgroup\$
1
\$\begingroup\$

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]
\$\endgroup\$
1
  • \$\begingroup\$ 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. \$\endgroup\$
    – Zgarb
    Commented Dec 16, 2016 at 11:33
1
\$\begingroup\$

[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
\$\endgroup\$
6
  • \$\begingroup\$ 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). \$\endgroup\$
    – Titus
    Commented Dec 16, 2016 at 15:28
  • \$\begingroup\$ @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. \$\endgroup\$
    – Dexa
    Commented Dec 16, 2016 at 16:18
  • \$\begingroup\$ Try unset($i);$A[+$i]. The + will cast null to integer 0. \$\endgroup\$
    – Titus
    Commented Dec 16, 2016 at 16:26
  • \$\begingroup\$ 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) \$\endgroup\$
    – Titus
    Commented Dec 16, 2016 at 16:39
  • \$\begingroup\$ @Titus Thanks a lot, it is shorter now. \$\endgroup\$
    – Dexa
    Commented Dec 16, 2016 at 16:52
1
\$\begingroup\$

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).

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

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
\$\endgroup\$
1
  • \$\begingroup\$ Could the nots be <1s instead? \$\endgroup\$
    – Zgarb
    Commented Dec 17, 2016 at 10:15
1
\$\begingroup\$

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
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Hi, 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],. \$\endgroup\$
    – Dennis
    Commented Dec 16, 2016 at 16:40
  • 1
    \$\begingroup\$ Welcome to PPCG! In addition to Dennis' specific tweaks, check out Tips for Golfing in Python to get some more general hints and tricks. \$\endgroup\$ Commented Dec 16, 2016 at 16:58
  • 1
    \$\begingroup\$ if and while statements do not need parenthesis. \$\endgroup\$
    – orlp
    Commented Dec 16, 2016 at 23:10
1
\$\begingroup\$

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))
\$\endgroup\$
1
\$\begingroup\$

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.

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

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;
\$\endgroup\$
0
\$\begingroup\$

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;
}
\$\endgroup\$
0
\$\begingroup\$

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}}
\$\endgroup\$
0
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

Jelly, 17 bytes

Ẉæl/
ẈḍⱮǧkṁ€ÇSƊṖ

Try it online!

How it works

Ẉæl/ - Helper link. Takes an array [A, B] on the left
Ẉ    - Lengths; [len(A), len(B)]
   / - Reduce by:
 æl  -   LCM
       This yields R := lcm(length(A), length(B))

ẈḍⱮǧkṁ€ÇSƊṖ - Main link. Takes [A, B] on the left
Ẉ            - [len(A), len(B)]
   Ç         - Call the helper link on [A, B]
  Ɱ          - Over each integer i = 1, 2, ..., R:
 ḍ           -   Yield [x, y] where:
                   x = 1 if len(A) % i == 0 else 0
                   y = 1 if len(B) % i == 0 else 0
    §        - For each pair, yield 0 if x = y = 0 else a non-zero element
          Ɗ  - To [A, B]:
        Ç    -   Yield R
       €     -   Over each element A, B:
      ṁ      -     Mold to length R
         S   -   Columnwise sums
     k       - Partition this array on the right at the non-zero indexes on the left
           Ṗ - Remove the trailing empty array
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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