24
\$\begingroup\$

zipwith is a functional construct that takes three arguments: one binary function and two lists of the same length, and returns a single list where each element is constructed by applying the binary function to each pair of elements from the two lists:

zipwith (a+b) [1,2,3] [4,5,6] = [5,7,9]

You are to take a black-box function which takes exactly two arguments and two non-empty arrays of the same length consisting of positive integers, and output the result of applying zipwith to this function and arrays.

For the sake of simplicity, you can assume that the black-box function will always input and output integers within your language's integer domain.

If your answer consists solely of a builtin which does this (for example Haskell's zipWith), please edit into this Community Wiki answer. You may input and output in any convenient method.

This is so the shortest code in bytes wins

Test Cases

function, array, array -> output
a = b, [1, 2, 3], [3, 2, 1] -> [0, 1, 0]
a - b, [8, 3], [3, 8] -> [5, -5]
a² + b/2, [6, 8, 1, 3], [5, 3, 6, 2] -> [38, 65, 4, 10]
a × φ(b), [4, 2, 5, 8, 3], [7, 6, 10, 2, 1] -> [24, 4, 20, 8, 3]

The third test case uses integer (floor) division. The fourth uses the Euler Totient function

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Sandbox \$\endgroup\$ Jan 26, 2021 at 11:04
  • 6
    \$\begingroup\$ +1 for the underhanded way to get people to implement the totient function. \$\endgroup\$
    – Adám
    Jan 26, 2021 at 11:48
  • 2
    \$\begingroup\$ @Adám Sneaky coding is the best coding :) \$\endgroup\$ Jan 26, 2021 at 11:49
  • \$\begingroup\$ Are integers in the list limited by my language's integer domain as well? \$\endgroup\$
    – user99151
    Jan 27, 2021 at 5:53
  • 1
    \$\begingroup\$ @2x-1 Yes. That restriction is just to allow as many languages to compete as possible \$\endgroup\$ Jan 27, 2021 at 7:04

41 Answers 41

14
\$\begingroup\$

Haskell, 22 bytes

(.zip).(.).map.uncurry

Try it online!

Not particularly interesting, just a reimplementation of zipWith converted to pointfree form:

\f x y -> map (uncurry f) (zip x y)
\f x -> map (uncurry f) . zip x
\f x -> (map (uncurry f) .) zip x
\f -> (map (uncurry f) .) . zip
\f -> (. zip) (map (uncurry f) .)
\f -> (. zip) ((.) (map (uncurry f)))
\f -> (. zip) ((.) ((map . uncurry) f))
\f -> (. zip) ((.) . (map . uncurry) $ f)
\f -> (. zip) . ((.) . (map . uncurry)) $ f
(. zip) . ((.) . (map . uncurry))
\$\endgroup\$
2
  • 3
    \$\begingroup\$ Welcome to the site! Nice first answer! \$\endgroup\$ Jan 27, 2021 at 0:10
  • 1
    \$\begingroup\$ @RedwolfPrograms, thank you! Been lurking for a while now ;-) \$\endgroup\$ Jan 27, 2021 at 0:11
11
\$\begingroup\$

Trivial builtin answers

Edit your answer into this post if it consists of a builtin which does the entire task by itself


HBL, 0.5 bytes

2

(Not implemented in the online version at the time of this writing.)

Fig, \$1\log_{256}(96)\approx\$ 0.823 bytes

z

Try it online!

Same as Husk.

APL (Dyalog Unicode), 1 byte

¨

Try it online!

BQN, 1 byte

¨

Same as APL. Try it at BQN online!

Husk, 1 byte

z

Try it online!

Jelly, 1 byte

"

Try it online!

J, 2 bytes

"0

Try it online!

Not technically a builtin, but close enough.

C#, 3 bytes

Zip

Try it online!

Julia, 3 bytes

map

Try it online!

Python 2, 3 bytes

map

Try it online!

R, 3 bytes

Map

Try it online!

The canonical R built-in function is mapply (6 bytes).
However, the R documentation for Map reads "Map is a simple wrapper to mapply which does not attempt to simplify the result" (meaning that Map leaves its output as a list, rather than a vector, of results), so this seems to be a perfectly-acceptable 3-byte alternative here.

Factor, 4 bytes

2map

Try it online!

Raku, 4 bytes

&zip

Try it online!

Haskell, 7 bytes

zipWith

Try it online!

Prolog (SWI), 7 bytes

maplist

Try it online!

MATLAB / Octave, 8 bytes

arrayfun

Try it online!

Elm, 9 bytes

List.map2

PHP, 9 bytes

array_map

Try it online! (PHP's array_map can take any number of array arguments)

Wolfram Language (Mathematica), 9 bytes

MapThread

Try it online!

tinylisp, 18 bytes

Not exactly a builtin, but a library function:

map*

4 bytes for the function, 14 bytes for (load library). Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ Should this answer not be sorted by byte count? \$\endgroup\$
    – Adám
    Jan 26, 2021 at 11:37
  • 4
    \$\begingroup\$ @Adám If people want to edit it around to be in byte count order, they are welcome to. So far, it's just been first-come, first-serve I believe \$\endgroup\$ Jan 26, 2021 at 11:37
  • \$\begingroup\$ Racket: docs.racket-lang.org/heresy/…. I don’t have the TIO or anything so someone else can feel free to add it; otherwise I’ll leave it here. \$\endgroup\$ Jan 26, 2021 at 22:55
  • \$\begingroup\$ @D.BenKnoble You can use JSDoodl or ideone too (I don't know Racket, or I would have added it in). \$\endgroup\$
    – user
    Jan 27, 2021 at 1:15
8
\$\begingroup\$

C (gcc), 49 bytes

z(f,a,b,n)int*a,*b,(*f)();{for(;n--;f(a++,b++));}

Try it online!

Loops for 0-n, applying f on &a[i], &b[i]. Fairly simple.

Ungolfed signature:

void zipwith(void (*blackbox)(int *, int *), int *a, int *b, int length);

This version expects a function like this:

void func(int *a, int *b)
{
    *a = *a OP *b;
}

It overwrites the contents in a.

Since this is a pretty loose interpretation of the rules, I have also provided a more strict version which acts like a normal zipwith.

C (gcc) strict, 61 54 bytes

z(f,a,b,n)int*a,*b,(*f)();{for(;n--;*a++=f(*a,*b++));}

Try it online!

Loops for 0-n, storing the result of f on a[i], b[i] to a[i]. Fairly simple.

Degolfed signature:

void zipwith(int (*blackbox)(int, int), int *a, int *b, int length);

Thanks to @att for reminding me I don't need a separate output array, saving 7 bytes.

\$\endgroup\$
2
7
\$\begingroup\$

Husk, 2 bytes

δm

Try it online! (Implement the function in the footer, the header passes it to the main code)

Sure, Husk has a trivial builtin solution for this (z), but here's the shortest interesting solution :)

δ is a higher order function that turns something using an unary function on elements of one list into one using a binary function on elements from two lists.

Here, we turn the map function m that applies the (unary) input function to each element of the input list into one that applies the (binary) input function to each pair of elements from the two input lists: exactly what zipWith should do!

\$\endgroup\$
7
\$\begingroup\$

x86-16 machine code, 15 14 bytes

Saved 1 byte thanks to @Joshua!

AD 50 87 F3 AD 50 87 F3-FF D2 AB E2 F3 C3

Callable function.

Inputs:

  • CX = lengths of both lists
  • [SI] = address of first list
  • [BX] = address of second list
  • [DX] = address of function

Outputs towards [DI] = address of output list (buffer needs to be large enough).

Disassembly:

       LoopTop:
AD            LODSW           ; AX = [SI], SI+=2
50            PUSH    AX      ; push AX onto stack
87 F3         XCHG    SI, BX  ; swap SI and BX
AD            LODSW           ; AX = [SI], SI+=2
50            PUSH    AX      ; push AX onto stack
87 F3         XCHG    SI, BX  ; swap SI and BX
FF D2         CALL    DX      ; call function at [DX]
                              ; the function should take two items on the stack
                              ; and AX = the return value (stock calling convention)
AB            STOSW           ; [DI] = AX, DI+=2
E2 F3         LOOP    LoopTop ; --CX; jump to top of loop while CX >= 0
C3            RET             ; return to caller

Example run

Tested with DOS debug:

-r
AX=0000  BX=0040  CX=0003  DX=0060  SP=FFFE  BP=0000  SI=0030  DI=0050
DS=1000  ES=1000  SS=0B17  CS=1000  IP=0000   NV UP EI PL NZ NA PO NC
1000:0000 AD            LODSW
-u1000:0060
1000:0060 58            POP     AX
1000:0061 A37600        MOV     [0076],AX
1000:0064 58            POP     AX
1000:0065 A37800        MOV     [0078],AX
1000:0068 58            POP     AX
1000:0069 01067800      ADD     [0078],AX
1000:006D A17600        MOV     AX,[0076]
1000:0070 50            PUSH    AX
1000:0071 A17800        MOV     AX,[0078]
1000:0074 C3            RET
-t
AX=0004  BX=0030  CX=0003  DX=0060  SP=FFFF  BP=0000  SI=0042  DI=0050
DS=1000  ES=1000  SS=0B17  CS=1000  IP=0001   NV UP EI PL NZ NA PO NC
1000:0001 50            PUSH    AX
-t
AX=0004  BX=0030  CX=0003  DX=0060  SP=FFFD  BP=0000  SI=0042  DI=0050
DS=1000  ES=1000  SS=0B17  CS=1000  IP=0002   NV UP EI PL NZ NA PO NC
1000:0002 87F3          XCHG    SI,BX
...
-t
AX=0009  BX=0036  CX=0000  DX=0060  SP=FFFF  BP=0000  SI=0046  DI=0056
DS=1000  ES=1000  SS=0B17  CS=1000  IP=000D   NV UP EI PL NZ NA PE NC
1000:000D C3            RET
-d1000:0000
1000:0000  AD 50 87 F3 AD 50 87 F3-FF D2 AB E2 F3 C3 00 19   .P...P..........
1000:0010  00 00 00 00 00 00 00 20-20 20 20 20 20 20 20 20   .......
1000:0020  20 20 20 20 20 20 20 20-20 20 00 00 00 00 00 00             ......
1000:0030  01 00 02 00 03 00 00 00-00 00 00 00 00 00 00 00   ................
1000:0040  04 00 05 00 06 00 00 00-00 00 00 00 00 00 00 00   ................
1000:0050  05 00 07 00 09 00 00 00-00 00 00 00 00 00 00 00   ................
1000:0060  58 A3 76 00 58 A3 78 00-58 01 06 78 00 A1 76 00   X.v.X.x.X..x..v.
1000:0070  50 A1 78 00 C3 00 0A 00-09 00 00 00 00 00 00 00   P.x.............
\$\endgroup\$
1
  • 3
    \$\begingroup\$ Save a byte by using the stock calling convention; return value already in AX. Pushing a return value onto the stack is really ugly. \$\endgroup\$
    – Joshua
    Jan 27, 2021 at 20:33
6
\$\begingroup\$

Rust, 34 bytes

|f,a,b|a.into_iter().zip(b).map(f)

Try it online!

Rust doesn't have a zipwith function but it does have a zip and a map function. Returns an iterator over the values.

\$\endgroup\$
6
\$\begingroup\$

GNU-C-Preprocessor, 90 + O(48*n) Bytes

There should be code golf challenges for C preprocessor only, my idea:

#define T(x,...) x
#define D(x,y...) y
#define A(f,x,y) f(x,y)
#define Z5(f,x,y) A(f,T x,T y),Z4(f,(D x),(D y))
#define Z4(f,x,y) A(f,T x,T y),Z3(f,(D x),(D y))
#define Z3(f,x,y) A(f,T x,T y),Z2(f,(D x),(D y))
#define Z2(f,x,y) A(f,T x,T y),Z1(f,(D x),(D y))
#define Z1(f,x,y) A(f,T x,T y)

This example works for input lists of length <= 5. You can call the function like this:

#define C(x,y) x##y
(Z5(C,(h,e,l,l,o),(w,o,r,l,d)))

which results in

(hw,eo,lr,ll,od)

The "n" is the maximum list length to process and output. Of course you could use single characters instead of "Z" as name but using a digit allows for more flexibility and easier maintenance. For example you could add a parameter for "Z" to specify the bounds which is concatenated as Z##n and used as nested macro call.

The C Preprocessor opens a new realm of languages for code golf and is a rather minimal pure-functional primitive-recursive programming language which only features macro substitutions (which look like function calls, '(', ')', ',' and '#' are the only characters with special meaning), stringification, character concatenation (must be result in valid C tokens) and no direct recursion (each call must be defined with different macro name). Primitive-recursive means, it uses inputs of strictly bounded or fixed lengths and the program always terminates for all inputs. If you want a program for unbounded length, you would need an infinite program but program inputs are always bounded in practice. Literally any strictly limited output for strictly limited input values can be programmed by a primitive-recursive program and thus the C preprocessor. The program only must be big enough to compute it. It can become quite memory-inefficient though.


GNU-C Preprocessor, 238 + O(32*log3(n)) Bytes

A more optimal program size with O(log(n)) program growth is possible but requires hacky additional macro definitions and will only pay off starting with slightly larger input lists. This example purposefully does not add commas between elements in the output to allow for higher flexibility in output.

#define L4(p) L3(p) L3(p) L3(p)
#define L3(p) L2(p) L2(p) L2(p)
#define L2(p) L1(p) L1(p) L1(p)
#define L1(p) p() p() p()

#define T(x,...) x
#define D(x,y...) y
#define I(x...) x
#define W(r,f,a,b,x,y) (I r f(a,b)),f,x,y
#define X(r,f,x,y) W(r,f,T x,T y,(D x),(D y))
#define Y(x...) X(x)
#define C() )
#define O() (
#define U(x...) T(x)
#define Z(f,x,y) U(U(L4(Y O)(),f,x,y L4(C)))

Explanation:

  • L<x> is the loop and <x> is the exponent of how often to loop.
  • T,U = take first element from comma-separated list
  • D = drop first element from comma-separated list
  • I = identity function (evaluates arguments and can remove parens)
  • A = applies a function but without lazy argument-evaluation
  • X,Y,Z = the actual zipWith function
  • C = closing parenthesis, needed for code generation
  • O = opening parenthesis, needed for code generation (prevents unclosed macro call errors)

The main idea is to code-generate a long nested expression in a loop so that Z(args) evaluates to literally Y ( Y ( Y ( ... args' ...) ) ) and Y reduces the arguments by one step when evaluated in U(U(...)) (it does not work with only one U).

This example can process up to 3^4 = 243 elements of two lists. If you want to multiply the processing limit by 3, add a new loop line on the top of the code. You need about 20 loop lines to handle unsigned 32-bit of elements. But keep in mind that each element is evaluated, even if does not exist! This is an example which zip-concatenates elements of two lists and places a comma between elements iff the concatenation is not empty:

#define V2(x...) ,##x
#define V(x...) V2(x)
#define CONC(x,y...) y##x
#define CONC1(x,y) V(CONC(y,x))
#define D2(x) (D x)
D2(Z(CONC1,(h,e,l,l,o),(w,o,r,l,d)))

The result is (hw ,eo ,lr ,ll ,od) . It works with any lists with any number of elements but will output at most 243 elements. Tested on godbolt.org.

If you find improvements which aren't only shorter macro names, please feel free to update this answer and leave a comment.

\$\endgroup\$
2
  • 3
    \$\begingroup\$ Welcome to the site, and nice first answer! \$\endgroup\$ Jan 27, 2021 at 21:45
  • \$\begingroup\$ And a nice tutorial on a language that is ignored and underappreciated. My only attempt at doing anything with the C preprocessor was implement a max() function, 30 years ago. \$\endgroup\$ Jan 29, 2021 at 0:39
6
\$\begingroup\$

R, 32 bytes

function(f,x,y)Vectorize(f)(x,y)

Try it online!

If R didn't already have a built-in (mapply/Map) for zipwith, here's how one could implement it in 32 bytes...
(...and if R didn't have Vectorize, we'd need to implement it the 'hard' way for 54 bytes: function(f,x,y){for(i in seq(a=x))T[i]=f(x[i],y[i]);T})

\$\endgroup\$
4
  • 1
    \$\begingroup\$ I would argue this makes Vectorize an equivalent built-in solution to this problem, except that its first input is curried \$\endgroup\$
    – pxeger
    Jan 26, 2021 at 11:38
  • \$\begingroup\$ @pxeger - I kind-of agree, ish, so I've now included a 'do it the hard way' version, too... \$\endgroup\$ Jan 26, 2021 at 11:40
  • 1
    \$\begingroup\$ I think Map would also work for R as a built-in, since it's really just Map=function(f,...)mapply(FUN=f...,simplify=FALSE) \$\endgroup\$
    – Giuseppe
    Jan 26, 2021 at 17:02
  • \$\begingroup\$ @Giuseppe - you're absolutely right! I always seem to forget about Map. I've edited it into the 'trivial builtin answers' answer. Thanks for the reminder... \$\endgroup\$ Jan 26, 2021 at 17:40
5
\$\begingroup\$

Husk, 5 bytes

mF₁Te

Try it online!

Takes the two arrays as arguments, and the function in the footer. You can use any binary function which operates on two TNums from Husk's Commands page.

Explanation

mF₁Te Main program: accepts two arrays
    e two element list from the arrays
   T  transpose
m     map each pair to
 F    itself folded by
  ₁   the black box function
\$\endgroup\$
4
  • 2
    \$\begingroup\$ Yeah, that's why I submitted a non-trivial solution. \$\endgroup\$
    – Razetime
    Jan 26, 2021 at 12:15
  • \$\begingroup\$ Ah ok, thought you might have overlooked the builtin answer accidently. Carry on. :) \$\endgroup\$ Jan 26, 2021 at 12:17
  • \$\begingroup\$ What if the black box function isn't representable as a single builtin? \$\endgroup\$
    – Joshua
    Jan 26, 2021 at 20:11
  • \$\begingroup\$ @Joshua - This still works fine. For instance, test case 3... \$\endgroup\$ Jan 26, 2021 at 23:43
5
\$\begingroup\$

Factor, 24 bytes

[ zip swap f assoc>map ]

Try it online!

Avoids the obvious built-in 2map and its trivial generalizations nmap and 2map-as, and uses zip and assoc>map instead (so it works like e.g. the Rust answer). Takes the input from the stack in the order of func arr1 arr2.

Small golfing tip: when using a function that takes an "exemplar" (which specifies the type of the output container), supplying f has the same effect as supplying { } (a plain array).

Factor, using nmap, 10 bytes

[ 2 nmap ]

Try it online!

nmap is a generalized version of map-family of functions that works with n input arrays and n-ary functions. Obviously, 2 nmap works on two input arrays and binary functions.

Factor, using 2map-as, 13 bytes

[ f 2map-as ]

Try it online!

2map-as is a simple variation of 2map that takes an exemplar.

2map itself is already listed in the trivial built-in catalogue.

\$\endgroup\$
1
  • \$\begingroup\$ f means { } as an exemplar? Whaaaaaaat. That's awesome. \$\endgroup\$
    – chunes
    Apr 28, 2021 at 2:17
5
\$\begingroup\$

GNU sed, 55 + 1(r flag) = 56 bytes

GNU sed doesn't even have integers, not to mention functions, lists / arrays, etc. In order to participate, I used the following assumptions for the I/O methods, which hopefully respect the consensus regarding sed:

  1. each input list / array is given on a separate input line, with the integers separated by space.
  2. the black-box function is predefined under the label f.
  3. the black-box function arguments are two space separated integers read from the first pattern space line (generated there at runtime during each iteration).
  4. the return value of the black-box function is placed on the first pattern space line
  5. the output list / array is given as one integer per line.
1N                                            # read the 2nd input list
s:([^ ]+) ?(.*\n)([^ ]+) ?(.*):\1 \3\n\2\4:   # put list1[i] and list2[i] on first line
tf;:                                          # call the black-box function `f`
P                                             # print the function return value
D                                             # delete return value, start new iteration

Try it online with sed 4.2.2!

The implemented black-box function in the link above is a == b. The other test functions are significantly harder to implement in sed, but possible since the language is Turing complete.

\$\endgroup\$
4
\$\begingroup\$

JavaScript (ES6), 32 bytes

(F,a,b)=>a.map((x,i)=>F(x,b[i]))

Try it online!

\$\endgroup\$
4
\$\begingroup\$

Zsh, 24 bytes

for 1 2 (`paste $@`)f $@

Try it online!

Uses a black-box function named f, with input from two files specified in command line arguments.

However, paste alone is really just a zip, and this brings up some interesting debate depending on your interpretation of what counts as a "function" under the Unix philosophy of "everything should be a text stream":

#!/bin/zsh

# using a predefined function F
z1() { paste $1 $2 | F }
# using a function named in the arguments
z2() { paste $1 $2 | $3 }

F() { while read line; do rev <<< line; done }
z1 input1 input
z2 input1 input2 F
paste input1 input2 | F
paste input1 input2 | rev

# so maybe paste is just a point-free function?
paste

So maybe this is a trivial built-in solution:

Unix shell (?), 5 bytes (?)

paste
\$\endgroup\$
2
4
\$\begingroup\$

Java 8, 52 bytes

A->B->{for(int l=A.length;l-->0;)A[l]=f(A[l],B[l]);}

Puts the result in the first argument instead of returning a new integer-array (to save 25 bytes).

Try it online.

Explanation:

A->B->{                     // Method with two integer-array parameters & no return-type
  for(int l=A.length;l-->0;)//  Loop `l` in the range (length,0]:
    A[l]=                   //   Change the `l`'th item in the first array to:
      f(                    //    Call the black-box function `f`
        A[l],B[l]);}        //    with the `l`'th items of both arrays as parameters

Black box input format:

Assumes a named function Object f(Object a,Object b) is present, which is allowed according to this meta answer.

I have an abstract class Test containing the default function f(a,b), as well as the lambda above:

abstract class Test{
  Object f(Object a,Object b){
    return(int)a+(int)b;
  }

  public java.util.function.Function<Object[], java.util.function.Consumer<Object[]>>c=
    A->B->{for(int l=A.length;l-->0;)A[l]=f(A[l],B[l]);}
  ;
}

For the test cases, I overwrite this function f. For example, the third test case (which is responsible for the black-box having Object as parameters/return-type instead of int) is called like this:

Object[] a = new Object[]{1,2,3};
new Test(){
  @Override
  Object f(Object a,Object b){
    return a==b;
  }
}.c.apply(a).accept(new Object[]{3,2,1});
System.out.println(java.util.Arrays.toString(a));
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Using a predefined function is no longer valid in Java, as since Java 8 it is possible to pass the function as a parameter. The meta answer in your link does not apply here. \$\endgroup\$
    – Donat
    Jan 31, 2021 at 14:48
  • \$\begingroup\$ It'll just cost a couple bytes to use (f,A,B)->, right? \$\endgroup\$
    – user
    Jan 31, 2021 at 17:48
  • 1
    \$\begingroup\$ @user Not really.. It would be 68 bytes in that case, since you also need two .apply() to use lambda f. :/ Which is why I think meta rules of the form "If X isn't possible, use Y instead" are unfair for any language where both are possible, but Y would be shorter.. If we're allowed to pass an interface as argument instead of Function it could be 57 bytes. Although an interface is technically not a function, so no idea if it's allowed.. (Using Java 7 without lambdas at all would be 73 bytes.) \$\endgroup\$ Jan 31, 2021 at 18:34
4
\$\begingroup\$

Nim, 71 70 bytes

iterator z[I](f:proc(x,y:I):I;a,b:seq):I=
 for i,x in a:yield x.f b[i]

Try it online!

\$\endgroup\$
4
\$\begingroup\$

Idris - 77 bytes

z:(a->b->c)->List a->List b->List c
z f(x::v)(y::w)=f x y::z f v w
z _ _ _=[]
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Welcome to the site, and nice first answer! \$\endgroup\$ Jan 27, 2021 at 16:32
  • 2
    \$\begingroup\$ I don't know Idris, but if the pattern matching works like in Haskell, you should be able to remove the first two patterns and append z _ _ _=[] at the end. \$\endgroup\$
    – ovs
    Jan 27, 2021 at 16:40
  • 1
    \$\begingroup\$ Welcome to Code Golf! I would suggest linking to Try it Online or other online interpreters along with your answer. Here is a 77 byte version of your answer. As @ovs said, you can collapse the first two patterns into one because the lists are guaranteed to be of the same length. \$\endgroup\$
    – user
    Jan 27, 2021 at 16:47
  • \$\begingroup\$ @ovs user Ah I appreciate the advice, I learnt a new technique for programming in Idris and better codegolf etiquette because of both of you! I've updated the answer accordingly. \$\endgroup\$
    – nicoty
    Jan 27, 2021 at 19:01
3
\$\begingroup\$

Stax, 6 bytes invocable, or 3 bytes toplevel

Does not make sense to compress functions in stax so I didn't.

The two arrays are passed on the stack, and the black-box function is passed in the x register.

|\{x!m

Explained:

|\                Zip input arrays
  {
   x              push contents of x register
    !             invoke top of stack
  m               map
    

Program head version: two arrays are passed to it on the stack; body of blackbox program follows

|\m

Explained:

|\                Zip input arrays
  m               map array with rest of program
\$\endgroup\$
3
\$\begingroup\$

Wolfram Language (Mathematica), 11 bytes

Inner[##,]&

Try it online!

Returns a Null of results.

Inner almost does zipwith - except, by default, it returns the sum of the results.


Also 11 bytes

#@@@In@@#2&

Try it online!

In (among others) is as short as a built-in Listable function gets, and remains unevaluated with >1 argument.

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

Red, 69 bytes

func[a b f][collect[repeat i length? a[keep compose[(f a/:i b/:i)]]]]

Try it online!

Printing the result instead of returning it:

61 bytes

func[a b f][repeat i length? a[print compose[(f a/:i b/:i)]]]

Try it online!

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

Racket, 41 bytes

(λ(x y f)(for/list([i x][j y])(f i j))))

Try it online!

for/list is almost the necessary builtin, just needs some additional syntax.

\$\endgroup\$
6
  • 1
    \$\begingroup\$ zipwith \$\endgroup\$ Jan 26, 2021 at 22:56
  • \$\begingroup\$ @D.BenKnoble That would go into the Trivial Answers CW answer, right? \$\endgroup\$
    – user
    Jan 26, 2021 at 23:54
  • 1
    \$\begingroup\$ @user yes, left a comment there too. \$\endgroup\$ Jan 27, 2021 at 1:03
  • \$\begingroup\$ @D.BenKnoble I know just a little Racket. I'm sure I searched for zipwith (and just zip) in the local documentation and I didn't find anything. Now I see that zipwith is not part ot the core Racket, but of a langauge called "Heresy". \$\endgroup\$ Jan 27, 2021 at 7:45
  • 2
    \$\begingroup\$ @GalenIvanov yeah I didnt even notice it was until I looked harder at the link I posted. Sorry \$\endgroup\$ Jan 27, 2021 at 12:46
2
\$\begingroup\$

Scala 3 (compile time), 87 bytes

type Z[F[_,_],A<:Tuple,B]<:Tuple=(A,B)match{case(a*:b,c*:d)=>F[a,c]*:Z[F,b,d]case _=>A}

Try it online!

Takes tuples instead of lists.

This isn't particulary interesting or complicated, but here's an explanation:

type Z[                //Declare a type Z taking these arguments
  F[_,_],              //A type F that itself takes two arguments
  A <: Tuple,          //The first list, a tuple
  B                    //The second list (actually also a tuple)
] <: Tuple =           //The returned type is also a tuple
  (A, B) match {       //Make a tuple (A, B) and match it:
  //`h*:t` represents a tuple with head `h` and tail `t` (like :: or :)
  case (a *: b, c *: d) => //If A is of the form a*:b and B is of the form c*:d
    F[a, c]         //Call F on the heads
      *:            //And prepend that to
      Z[F, b, d]    //The result of zipping the rest of the tuples
  case _ => A //Otherwise, both tuples are empty, so we return an empty tuple
  }
\$\endgroup\$
2
\$\begingroup\$

Pure Zsh, 31 bytes

b=($=3)
for 2 3 (${${=2}:^b})$@

Try it online!

Takes parameters function name, space-delimited list, space-delimited list

With -o shwordsplit, one byte is saved with b=($3) instead.

b=($=3)                  # =split $3 and save as array $b
#        ${${=2}:^b}     # Zip $=2 and $b together
for 2 3 (${${=2}:^b})    # Loop over 2 at a time as $2 and $3 (argv[2], argv[3])
    $@                   # $1 $2 $3
\$\endgroup\$
2
\$\begingroup\$

Groovy, 36 bytes

{f,a,b->[a,b].transpose().collect f}

Try it online!

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

Python 3, 37 35 bytes

lambda f,*a:[f(*t)for t in zip(*a)]

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ You can save two bytes by using more *: lambda f,*a:[f(*t)for t in zip(*a)] \$\endgroup\$
    – ovs
    Jan 31, 2021 at 12:54
  • \$\begingroup\$ @ovs: how cool is that ?!?! Thanks. \$\endgroup\$
    – mhawke
    Jan 31, 2021 at 13:00
2
\$\begingroup\$

PowerShell, 93 bytes

function Z($F,$S,$R={,$args}){[Linq.Enumerable]::Zip($F,$S,[Func[Object,Object,Object[]]]$R)}

Example

Z (1,2,3) (4,5,6) {param($a, $b) ($a+$b)}
'-'
Z (8,3) (3,8) {param($a, $b) ($a-$b)}
'-'
Z (6,8,1,3) (5,3,6,2) {param($a, $b) ([math]::pow($a,2)+$b/2)}
'-'
Z (1,2,3) (3,2,1) {param($a, $b) ([int]($a-eq$b))}

Try it online!

It is a zip function which can take map expression as its third parameter to know how to pass it then see the demo in the Try it online "Footer" section how to use it.

\$\endgroup\$
1
  • \$\begingroup\$ you can save a lot of bytes if you use the dot source operator with scriptblocks \$\endgroup\$
    – mazzy
    Feb 1, 2021 at 6:07
2
\$\begingroup\$

Python 3, 19 bytes

lambda*l:[*map(*l)]

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Very nice answer! \$\endgroup\$
    – Donat
    Feb 1, 2021 at 14:10
2
\$\begingroup\$

Vyxal, 5 bytes

£Zƛ¥R

Try it Online!

I don't know how to input functions properly in Vyxal, so the Vyxal interpreter link just has the function stuffed with the code.

£Zƛ¥R
£     Set the register to the blackbox function
 Z    Zip the two lists
  ƛ   For each element of that
    R Reduce using
   ¥  The function in the register
\$\endgroup\$
2
\$\begingroup\$

Pip -xp, 5 bytes

aMZbc

Try It Online!

Explanation

This is essentially a built-in, the ternary MZ (map-zip) operator. However, I'm pretty sure a bare operator isn't a valid solution, so I've made it a full program. The -x flag allows functions and lists to be evaluated as such when passed as command-line arguments, and the -p flag means lists will be output in list format rather than concatenated together.

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

Icon, 52 bytes

procedure z(a,b,f)
write(f(a[i:=1to*a],b[i]))&\y
end

Try it online!

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

CJam, 8 bytes

l'.l++~p

Try it online! Or verify the first three cases: 1, 2, 3.

Input is a line with (the string representation of) two arrays, and then a line with (the string representation of) the function, defined as a CJam block.

How it works

l    e# Read line containing the two arrays
'.   e# Push character "." (which will do the actual job)
l    e# Read line containing a code block
++   e# Concatenate twice
~    e# Evaluate as CJam code
p    e# Print
\$\endgroup\$
1
  • \$\begingroup\$ Well if you can print your output rather than produce an output array, so can I. \$\endgroup\$
    – Joshua
    Jan 26, 2021 at 20:09

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.