Cartesian product of two or more lists: Difference between revisions

From Rosetta Code
Content added Content deleted
(Added scheme)
 
(42 intermediate revisions by 24 users not shown)
Line 21: Line 21:


<br>
<br>

=={{header|11l}}==
=={{header|11l}}==
{{trans|Go}}
{{trans|Go}}
<lang 11l>F cart_prod(a, b)
<syntaxhighlight lang="11l">F cart_prod(a, b)
V p = [(0, 0)] * (a.len * b.len)
V p = [(0, 0)] * (a.len * b.len)
V i = 0
V i = 0
Line 36: Line 35:
[Int] empty_array
[Int] empty_array
print(cart_prod([1, 2], empty_array))
print(cart_prod([1, 2], empty_array))
print(cart_prod(empty_array, [1, 2]))</lang>
print(cart_prod(empty_array, [1, 2]))</syntaxhighlight>
====Alternative version====
====Alternative version====
<lang 11l>F cart_prod(a, b)
<syntaxhighlight lang="11l">F cart_prod(a, b)
R multiloop(a, b, (aa, bb) -> (aa, bb))</lang>
R multiloop(a, b, (aa, bb) -> (aa, bb))</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 46: Line 45:
[]
[]
[]
[]
</pre>
=={{header|Action!}}==
<syntaxhighlight lang="action!">DEFINE MAX_COUNT="10"
DEFINE MAX_RESULT="100"

DEFINE PTR="CARD"

PROC PrintInput(PTR ARRAY a INT count)
INT i,j,n
INT ARRAY tmp

FOR i=0 TO count-1
DO
tmp=a(i) n=tmp(0)
Put('[)
FOR j=1 TO n
DO
PrintI(tmp(j))
IF j<n THEN Put(',) FI
OD
Put('])
IF i<count-1 THEN Put('x) FI
OD
RETURN

PROC PrintOutput(INT ARRAY a INT groups,count)
INT i,j,k

Put('[)
k=0
FOR i=0 TO groups-1
DO
Put('()
FOR j=0 TO count-1
DO
PrintI(a(k)) k==+1
IF j<count-1 THEN Put(',) FI
OD
Put('))
IF i<groups-1 THEN Put(',) FI
OD
Put('])
RETURN

PROC Product(PTR ARRAY a INT count
INT ARRAY r INT POINTER groups)
INT ARRAY ind(MAX_COUNT),tmp
INT i,j,k

IF count>MAX_COUNT THEN Break() FI
groups^=1
FOR i=0 TO count-1
DO
ind(i)=1 tmp=a(i)
groups^==*tmp(0)
OD
IF groups^=0 THEN RETURN FI
j=count-1 k=0
DO
FOR i=0 TO count-1
DO
tmp=a(i)
r(k)=tmp(ind(i)) k==+1
OD

DO
tmp=a(j)
IF ind(j)<tmp(0) THEN
ind(j)==+1
FOR i=j+1 TO count-1
DO
ind(i)=1
OD
j=count-1
EXIT
ELSE
IF j=0 THEN RETURN FI
j==-1
FI
OD
OD
RETURN

PROC Test(PTR ARRAY a INT count)
INT ARRAY r(MAX_RESULT)
INT groups

IF count<2 THEN Break() FI
Product(a,count,r,@groups)
PrintInput(a,count)
Put('=)
PrintOutput(r,groups,count)
PutE()
RETURN

PROC Main()
INT ARRAY
a1=[2 1 2],a2=[2 3 4],a3=[0],
a4=[2 1776 1789],a5=[2 7 12],
a6=[3 4 14 23],a7=[2 0 1],
a8=[3 1 2 3],a9=[1 30],a10=[2 500 100]
PTR ARRAY a(4)

a(0)=a1 a(1)=a2 Test(a,2)
a(0)=a2 a(1)=a1 Test(a,2)
a(0)=a1 a(1)=a3 Test(a,2)
a(0)=a3 a(1)=a1 Test(a,2) PutE()
a(0)=a4 a(1)=a5 a(2)=a6 a(3)=a7 Test(a,4) PutE()
a(0)=a8 a(1)=a9 a(2)=a10 Test(a,3) PutE()
a(0)=a8 a(1)=a3 a(2)=a10 Test(a,3)
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Cartesian_product_of_two_or_more_lists.png Screenshot from Atari 8-bit computer]
<pre>
[1,2]x[3,4]=[(1,3),(1,4),(2,3),(2,4)]
[3,4]x[1,2]=[(3,1),(3,2),(4,1),(4,2)]
[1,2]x[]=[]
[]x[1,2]=[]
[1776,1789]x[7,12]x[4,14,23]x[0,1]=[(1776,7,4,0),(1776,7,4,1),(1776,7,14,0),(1776,7,14,1),(1776,7,23,0),(1776,7,23,1),(1776,12,4,0),1776,12,4,1),(1776,12,14,0),(1776,12,14,1),(1776,12,23,0),(1776,12,23,1),(1789,7,4,0),(1789,7,4,1),(1789,7,14,0),(1789,7,14,1),(1789,7,23,0),(1789,7,23,1),(1789,12,4,0),(1789,12,4,1),(1789,12,14,0),(1789,12,14,1),(1789,12,23,0),(1789,12,23,1)]
[1,2,3]x[30]x[500,100]=[(1,30,500),(1,30,100),(2,30,500),(2,30,100),(3,30,500),(3,30,100)]
[1,2,3]x[]x[500,100]=[]
</pre>
=={{header|Ada}}==
<syntaxhighlight lang="ada">with Ada.Text_IO; use Ada.Text_Io;
with Ada.Containers.Doubly_Linked_Lists;
with Ada.Strings.Fixed;

procedure Cartesian is

type Element_Type is new Long_Integer;

package Lists is
new Ada.Containers.Doubly_Linked_Lists (Element_Type);
package List_Lists is
new Ada.Containers.Doubly_Linked_Lists (Lists.List, Lists."=");

subtype List is Lists.List;
subtype List_List is List_Lists.List;

function "*" (Left, Right : List) return List_List is
Result : List_List;
Sub : List;
begin
for Outer of Left loop
for Inner of Right loop
Sub.Clear;
Sub.Append (Outer);
Sub.Append (Inner);
Result.Append (Sub);
end loop;
end loop;
return Result;
end "*";

function "*" (Left : List_List;
Right : List) return List_List
is
Result : List_List;
Sub : List;
begin
for Outer of Left loop
for Inner of Right loop
Sub := Outer;
Sub.Append (Inner);
Result.Append (Sub);
end loop;
end loop;
return Result;
end "*";

procedure Put (L : List) is
use Ada.Strings;
First : Boolean := True;
begin
Put ("(");
for E of L loop
if not First then
Put (",");
end if;
Put (Fixed.Trim (E'Image, Left));
First := False;
end loop;
Put (")");
end Put;

procedure Put (LL : List_List) is
First : Boolean := True;
begin
Put ("{");
for E of LL loop
if not First then
Put (",");
end if;
Put (E);
First := False;
end loop;
Put ("}");
end Put;

function "&" (Left : List; Right : Element_Type) return List is
Result : List := Left;
begin
Result.Append (Right);
return Result;
end "&";

Nil : List renames Lists.Empty_List;
List_1_2 : constant List := Nil & 1 & 2;
List_3_4 : constant List := Nil & 3 & 4;
List_Empty : constant List := Nil;
List_1_2_3 : constant List := Nil & 1 & 2 & 3;
begin
Put (List_1_2 * List_3_4); New_Line;

Put (List_3_4 * List_1_2); New_Line;

Put (List_Empty * List_1_2); New_Line;

Put (List_1_2 * List_Empty); New_Line;

Put (List'(Nil & 1776 & 1789) * List'(Nil & 7 & 12) *
List'(Nil & 4 & 14 & 23) * List'(Nil & 0 & 1)); New_Line;

Put (List_1_2_3 * List'(Nil & 30) * List'(Nil & 500 & 100)); New_Line;

Put (List_1_2_3 * List_Empty * List'(Nil & 500 & 100)); New_Line;
end Cartesian;</syntaxhighlight>
{{out}}
<pre>{(1,3),(1,4),(2,3),(2,4)}
{(3,1),(3,2),(4,1),(4,2)}
{}
{}
{(1776,7,4,0),(1776,7,4,1),(1776,7,14,0),(1776,7,14,1),(1776,7,23,0),(1776,7,23,1),(1776,12,4,0),(1776,12,4,1),(1776,12,14,0),(1776,12,14,1),(1776,12,23,0),(1776,12,23,1),(1789,7,4,0),(1789,7,4,1),(1789,7,14,0),(1789,7,14,1),(1789,7,23,0),(1789,7,23,1),(1789,12,4,0),(1789,12,4,1),(1789,12,14,0),(1789,12,14,1),(1789,12,23,0),(1789,12,23,1)}
{(1,30,500),(1,30,100),(2,30,500),(2,30,100),(3,30,500),(3,30,100)}
{}</pre>
=={{header|ALGOL 68}}==
Using a 1-dimensional array of INT to represent a list and a 2-dimensional array ( [,]INT ) to represent a product of two (or more) lists.
<br>
A list of lists is represented by a 1-dimensional array of 1-dimensional arrays of INT ([][]INT).
<syntaxhighlight lang="algol68">
BEGIN # Cartesian Product #
# Cartesian product operators #
PRIO X = 7; # give X he same priority as * #
# returns the Cartesian product of the lists a and b #
OP X = ( []INT a, b )[,]INT:
BEGIN
[]INT a1 = a[ AT 1 ];
[]INT b1 = b[ AT 1 ];
INT len = UPB a1 * UPB b1;
[ 1 : len, 1 : IF len > 0 THEN 2 ELSE 0 FI ]INT result;
INT pos := 0;
FOR i TO UPB a1 DO
FOR j TO UPB b1 DO
pos +:= 1;
result[ pos, 1 ] := a1[ i ];
result[ pos, 2 ] := b1[ j ]
OD
OD;
result
END # X # ;
# returns the Cartesian product of the Cartesian product a and list b #
OP X = ( [,]INT a, []INT b )[,]INT:
BEGIN
[,]INT a1 = a[ AT 1, AT 1 ];
[]INT b1 = b[ AT 1 ];
INT len = 1 UPB a1 * UPB b1;
INT width = IF len <= 0 THEN 0 ELSE 2 UPB a1 + 1 FI;
[ 1 : len, 1 : width ]INT result;
INT pos := 0;
FOR i TO 1 UPB a1 DO
FOR j TO UPB b1 DO
result[ pos +:= 1, 1 : width - 1 ] := a1[ i, : ];
result[ pos, width ] := b1[ j ]
OD
OD;
result
END # X # ;
# returns the Cartesian product of the lists in a #
OP X = ( [][]INT a )[,]INT:
IF UPB a <= LWB a
THEN # zero or 1 list #
[,]INT()
ELSE # 2 or more lists #
FLEX[ 1 : 0, 1 : 0 ]INT result := a[ LWB a ] X a[ LWB a + 1 ];
FOR i FROM LWB a + 2 TO UPB a DO
result := result X a[ i ]
OD;
result
FI # X # ;
# print a Cartesian product #
PROC print product = ( [,]INT p )VOID:
BEGIN
print( ( "[" ) );
STRING close := "]";
STRING open := "(";
FOR i FROM 1 LWB p TO 1 UPB p DO
STRING separator := open;
FOR j FROM 2 LWB p TO 2 UPB p DO
print( ( separator, whole( p[ i, j ], 0 ) ) );
separator := ","
OD;
open := "),(";
close := ")]"
OD;
print( ( close ) )
END # print product # ;
# print a list #
PROC print list = ( []INT t )VOID:
BEGIN
print( ( "[" ) );
STRING separator := "";
FOR i FROM LWB t TO UPB t DO
print( ( separator, whole( t[ i ], 0 ) ) );
separator := ","
OD;
print( ( "]" ) )
END # print list # ;
BEGIN # test the X operators #
# prints the product of two lists #
PROC print lxl = ( []INT a, b )VOID:
BEGIN
print list( a );print( ( "X" ) );print list( b );
print( ( "=" ) );print product( a X b );
print( ( newline ) )
END # print lxl # ;
# prints the product of a list of lists #
PROC print xll = ( [][]INT a )VOID:
IF LWB a < UPB a THEN
# non empty list of lists #
print list( a[ LWB a ] );
FOR i FROM LWB a + 1 TO UPB a DO
print( ( "X" ) );print list( a[ i ] )
OD;
print( ( "=" ) );print product( X a );
print( ( newline ) )
FI # print xll # ;
print lxl( ( 1, 2 ), ( 3, 4 ) );
print lxl( ( 3, 4 ), ( 1, 2 ) );
print lxl( ( 1, 2 ), () );
print lxl( (), ( 1, 2 ) );
print xll( ( ( 1776, 1789 ), ( 7, 12 ), ( 4, 14, 23 ), ( 0, 1 ) ) );
print xll( ( ( 1, 2, 3 ), ( 30 ), ( 500, 100 ) ) );
print xll( ( ( 1, 2, 3 ), (), ( 500, 100 ) ) )
END
END
</syntaxhighlight>
{{out}}
<pre>
[1,2]X[3,4]=[(1,3),(1,4),(2,3),(2,4)]
[3,4]X[1,2]=[(3,1),(3,2),(4,1),(4,2)]
[1,2]X[]=[]
[]X[1,2]=[]
[1776,1789]X[7,12]X[4,14,23]X[0,1]=[(1776,7,4,0),(1776,7,4,1),(1776,7,14,0),(1776,7,14,1),(1776,7,23,0),(1776,7,23,1),(1776,12,4,0),(1776,12,4,1),(1776,12,14,0),(1776,12,14,1),(1776,12,23,0),(1776,12,23,1),(1789,7,4,0),(1789,7,4,1),(1789,7,14,0),(1789,7,14,1),(1789,7,23,0),(1789,7,23,1),(1789,12,4,0),(1789,12,4,1),(1789,12,14,0),(1789,12,14,1),(1789,12,23,0),(1789,12,23,1)]
[1,2,3]X[30]X[500,100]=[(1,30,500),(1,30,100),(2,30,500),(2,30,100),(3,30,500),(3,30,100)]
[1,2,3]X[]X[500,100]=[]
</pre>
</pre>


Line 56: Line 411:
a matrix, and the task is asking for a list, you also need to ravel the result.
a matrix, and the task is asking for a list, you also need to ravel the result.


<lang APL>cart ← ,∘.,</lang>
<syntaxhighlight lang="apl">cart ← ,∘.,</syntaxhighlight>


{{out}}
{{out}}
Line 73: Line 428:
list of lists.
list of lists.


<lang APL>nary_cart ← ⊃(,∘.,)/</lang>
<syntaxhighlight lang="apl">nary_cart ← ⊃(,∘.,)/</syntaxhighlight>


{{out}}
{{out}}
Line 116: Line 471:


=={{header|AppleScript}}==
=={{header|AppleScript}}==
<lang AppleScript>-- CARTESIAN PRODUCTS ---------------------------------------------------------
<syntaxhighlight lang="applescript">-- CARTESIAN PRODUCTS ---------------------------------------------------------


-- Two lists:
-- Two lists:
Line 275: Line 630:
on unlines(xs)
on unlines(xs)
intercalate(linefeed, xs)
intercalate(linefeed, xs)
end unlines</lang>
end unlines</syntaxhighlight>
{{Out}}
{{Out}}
<pre>[[1, 3], [1, 4], [2, 3], [2, 4]]
<pre>[[1, 3], [1, 4], [2, 3], [2, 4]]
Line 310: Line 665:


[]</pre>
[]</pre>
=={{header|Arturo}}==
{{trans|Ruby}}
<syntaxhighlight lang="rebol">loop [
[[1 2][3 4]]
[[3 4][1 2]]
[[1 2][]]
[[][1 2]]
[[1776 1789][7 12][4 14 23][0 1]]
[[1 2 3][30][500 100]]
[[1 2 3][][500 100]]
] 'lst [
print as.code product.cartesian lst
]</syntaxhighlight>


{{out}}

<pre>[[1 3] [1 4] [2 3] [2 4]]
[[3 1] [3 2] [4 1] [4 2]]
[]
[]
[[1776 7 4 0] [1776 7 4 1] [1776 7 14 0] [1776 7 14 1] [1776 7 23 0] [1776 7 23 1] [1776 12 4 0] [1776 12 4 1] [1776 12 14 0] [1776 12 14 1] [1776 12 23 0] [1776 12 23 1] [1789 7 4 0] [1789 7 4 1] [1789 7 14 0] [1789 7 14 1] [1789 7 23 0] [1789 7 23 1] [1789 12 4 0] [1789 12 4 1] [1789 12 14 0] [1789 12 14 1] [1789 12 23 0] [1789 12 23 1]]
[[1 30 500] [1 30 100] [2 30 500] [2 30 100] [3 30 500] [3 30 100]]
[]</pre>
=={{header|AutoHotkey}}==
<syntaxhighlight lang="autohotkey">example := [
(join,
[[1, 2], [3, 4]]
[[3, 4], [1, 2]]
[[1, 2], []]
[[], [1, 2]]
[[1776, 1789], [7, 12], [4, 14, 23], [0, 1]]
[[1, 2, 3], [30] , [500, 100]]
[[1, 2, 3], [] , [500, 100]]
)]

for i, obj in example
{
Product := CartesianProduct(obj)
out := dispRes(Product)
result .= out "`n`n"
}
MsgBox % result
return

dispRes(Product){
for i, o in Product
{
for j, v in o
output .= v ", "
output := Trim(output, ", ")
output .= "], ["
}
return "[[" trim(output, ", []") "]]"
}

CartesianProduct(obj){
CP(obj, Product:=[], [])
return Product
}

CP(obj, Product, stack, v:=""){
oClone := obj.clone()
oClone.RemoveAt(1)
stack.= v ","
for i, o in obj
{
for j, v in o
CP(oClone, Product, stack, v)
return
}
stack := trim(stack, ",")
oTemp := []
for i, v in StrSplit(stack, ",")
oTemp.Push(v)
Product.push(oTemp)
}</syntaxhighlight>
{{out}}
<pre>[[1, 3], [1, 4], [2, 3], [2, 4]]
[[3, 1], [3, 2], [4, 1], [4, 2]]
[]
[]
[[1776, 7, 4, 0], [1776, 7, 4, 1], [1776, 7, 14, 0], [1776, 7, 14, 1], [1776, 7, 23, 0], [1776, 7, 23, 1], [1776, 12, 4, 0], [1776, 12, 4, 1], [1776, 12, 14, 0], [1776, 12, 14, 1], [1776, 12, 23, 0], [1776, 12, 23, 1], [1789, 7, 4, 0], [1789, 7, 4, 1], [1789, 7, 14, 0], [1789, 7, 14, 1], [1789, 7, 23, 0], [1789, 7, 23, 1], [1789, 12, 4, 0], [1789, 12, 4, 1], [1789, 12, 14, 0], [1789, 12, 14, 1], [1789, 12, 23, 0], [1789, 12, 23, 1]]
[[1, 30, 500], [1, 30, 100], [2, 30, 500], [2, 30, 100], [3, 30, 500], [3, 30, 100]]
[]</pre>
=={{header|Bracmat}}==
=={{header|Bracmat}}==
<lang Bracmat>( ( mul
<syntaxhighlight lang="bracmat">( ( mul
= R a b A B
= R a b A B
. :?R
. :?R
Line 346: Line 786:
& out$(cartprod$((.1 2 3) (.30) (.500 100)))
& out$(cartprod$((.1 2 3) (.30) (.500 100)))
& out$(cartprod$((.1 2 3) (.) (.500 100)))
& out$(cartprod$((.1 2 3) (.) (.500 100)))
)</lang>
)</syntaxhighlight>
<pre>. (.1776 7 4 0)
<pre>. (.1776 7 4 0)
(.1776 7 4 1)
(.1776 7 4 1)
Line 379: Line 819:
(.3 30 100)
(.3 30 100)
.</pre>
.</pre>

=={{header|BASIC}}==
==={{header|Applesoft BASIC}}===
{{works with|Chipmunk Basic}}
{{works with|GW-BASIC}}
<syntaxhighlight lang="qbasic">100 HOME : rem 10 CLS FOR Chipmunk Basic & GW-BASIC
110 DIM array(2,2)
120 array(1,1) = 1 : array(1,2) = 2
130 array(2,1) = 3 : array(2,2) = 4
140 GOSUB 190
150 array(1,1) = 3 : array(1,2) = 4
160 array(2,1) = 1 : array(2,2) = 2
170 GOSUB 190
180 END
190 rem SUB cartesian(list)
200 u1 = 2 : u2 = 2
210 FOR i = 1 TO u1
220 PRINT "{ ";
230 FOR j = 1 TO u2
240 PRINT array(i,j);
250 IF j < u1 THEN PRINT ", ";
260 NEXT j
270 PRINT "}";
280 IF i < u2 THEN PRINT " x ";
290 NEXT i
300 PRINT " = { ";
310 FOR i = 1 TO u1
320 FOR j = 1 TO u2
330 PRINT "{ "; array(1,i); ", "; array(2,j); "} ";
340 IF i < u2 THEN PRINT ", ";
350 IF i => u2 THEN IF j < u1 THEN PRINT ", ";
360 NEXT j
370 NEXT i
380 PRINT "}"
390 RETURN</syntaxhighlight>

==={{header|BASIC256}}===
<syntaxhighlight lang="vb">arraybase 1
subroutine cartesian(list)
u1 = list[?][]
u2 = list[][?]

for i = 1 to u1
print "{";
for j = 1 to u2
print list[i,j];
if j < u1 then print ", ";
next
print "}";
if i < u2 then print " x ";
next i
print " = { ";
for i = 1 to u1
for j = 1 to u2
print "{"; list[1, i]; ", "; list[2, j]; "} ";
if i < u2 then
print ", ";
else
if j < u1 then print ", ";
end if
next j
next i
print "}"
end subroutine

dim list1 = {{1,2},{3,4}}
dim list2 = {{3,4},{1,2}}
call cartesian(list1)
call cartesian(list2)
end</syntaxhighlight>
{{out}}
<pre>{1, 2} x {3, 4} = { {1, 3} , {1, 4} , {2, 3} , {2, 4} }
{3, 4} x {1, 2} = { {3, 1} , {3, 2} , {4, 1} , {4, 2} }</pre>

==={{header|Chipmunk Basic}}===
{{works with|Chipmunk Basic|3.6.4}}
<syntaxhighlight lang="qbasic">100 cls
110 dim array(2,2)
120 array(1,1) = 1 : array(1,2) = 2
130 array(2,1) = 3 : array(2,2) = 4
140 gosub 190
150 array(1,1) = 3 : array(1,2) = 4
160 array(2,1) = 1 : array(2,2) = 2
170 gosub 190
180 end
190 rem sub cartesian(list)
200 u1 = 2 : u2 = 2
210 for i = 1 to u1
220 print "{ ";
230 for j = 1 to u2
240 print array(i,j);
250 if j < u1 then print ", ";
260 next j
270 print "}";
280 if i < u2 then print " x ";
290 next i
300 print " = { ";
310 for i = 1 to u1
320 for j = 1 to u2
330 print "{ ";array(1,i);", ";array(2,j);"} ";
340 if i < u2 then
350 print ", ";
360 else
370 if j < u1 then print ", ";
380 endif
390 next j
400 next i
410 print "}"
420 return</syntaxhighlight>

==={{header|Gambas}}===
<syntaxhighlight lang="vbnet">Public array[2, 2] As Integer

Public Sub Main()
array[0, 0] = 1
array[0, 1] = 2
array[1, 0] = 3
array[1, 1] = 4
cartesian(array)
array[0, 0] = 3
array[0, 1] = 4
array[1, 0] = 1
array[1, 1] = 2
cartesian(array)
End

Sub cartesian(arr As Integer[])
Dim u1 As Integer = arr.Max - 2
Dim u2 As Integer = arr.Max - 2
Dim i As Integer, j As Integer
For i = 0 To u1
Print "{";
For j = 0 To u2
Print arr[i, j];
If j < u1 Then Print ",";
Next
Print "}";
If i < u2 Then Print " x ";
Next
Print " = {";
For i = 0 To u1
For j = 0 To u2
Print "{"; arr[0, i]; ","; arr[1, j]; "}";
If i < u2 Then
Print ", ";
Else
If j < u1 Then Print ", ";
End If
Next
Next
Print "}"
End Sub</syntaxhighlight>

==={{header|GW-BASIC}}===
{{works with|Chipmunk Basic}}
{{works with|PC-BASIC|any}}
{{works with|QBasic}}
{{works with|MSX-BASIC}}
<syntaxhighlight lang="qbasic">100 CLS
110 DIM ARR(2,2)
120 ARR(1,1) = (1) : ARR(1,2) = (2)
130 ARR(2,1) = (3) : ARR(2,2) = (4)
140 GOSUB 190
150 ARR(1,1) = 3 : ARR(1,2) = 4
160 ARR(2,1) = 1 : ARR(2,2) = 2
170 GOSUB 190
180 END
190 REM SUB cartesian(list)
200 U1 = 2 : U2 = 2
210 FOR I = 1 TO U1
220 PRINT "{";
230 FOR J = 1 TO U2
240 PRINT ARR(I,J);
250 IF J < U1 THEN PRINT ",";
260 NEXT J
270 PRINT "}";
280 IF I < U2 THEN PRINT " x ";
290 NEXT I
300 PRINT " = {";
310 FOR I = 1 TO U1
320 FOR J = 1 TO U2
330 PRINT "{"; ARR(1,I); ","; ARR(2,J); "}";
340 IF I < U2 THEN PRINT ", ";
350 IF I => U2 THEN IF J < U1 THEN PRINT ",";
360 NEXT J
370 NEXT I
380 PRINT "}"
390 RETURN</syntaxhighlight>

==={{header|MSX Basic}}===
{{works with|MSX BASIC|any}}
The [[#GW-BASIC|GW-BASIC]] solution works without any changes.

==={{header|QBasic}}===
{{works with|QBasic|1.1}}
{{works with|QuickBasic|4.5}}
<syntaxhighlight lang="qbasic">DECLARE SUB cartesian (arr!())

CLS
DIM array(2, 2)
array(1, 1) = 1: array(1, 2) = 2
array(2, 1) = 3: array(2, 2) = 4
CALL cartesian(array())
array(1, 1) = 3: array(1, 2) = 4
array(2, 1) = 1: array(2, 2) = 2
CALL cartesian(array())
END

SUB cartesian (arr())
u1 = 2: u2 = 2
FOR i = 1 TO u1
PRINT "{";
FOR j = 1 TO u2
PRINT arr(i, j);
IF j < u1 THEN PRINT ",";
NEXT j
PRINT "}";
IF i < u2 THEN PRINT " x ";
NEXT i
PRINT " = {";
FOR i = 1 TO u1
FOR j = 1 TO u2
PRINT "{"; arr(1, i); ","; arr(2, j); "}";
IF i < u2 THEN
PRINT ", ";
ELSE
IF j < u1 THEN PRINT ", ";
END IF
NEXT j
NEXT i
PRINT "}"
END SUB</syntaxhighlight>

==={{header|Run BASIC}}===
{{works with|Just BASIC}}
{{works with|Liberty BASIC}}
<syntaxhighlight lang="vb">cls
dim array(2,2)
array(1,1) = 1 : array(1,2) = 2
array(2,1) = 3 : array(2,2) = 4
gosub [cartesian]
array(1,1) = 3 : array(1,2) = 4
array(2,1) = 1 : array(2,2) = 2
gosub [cartesian]
end

[cartesian]
u1 = 2 : u2 = 2
for i = 1 to u1
print "{";
for j = 1 to u2
print array(i,j);
if j < u1 then print ",";
next j
print "}";
if i < u2 then print " x ";
next i
print " = {";
for i = 1 to u1
for j = 1 to u2
print "{"; array(1,i); ","; array(2,j); "}";
if i < u2 then
print ",";
else
if j < u1 then print ",";
end if
next j
next i
print "}"
return</syntaxhighlight>


=={{header|C}}==
=={{header|C}}==
Recursive implementation for computing the Cartesian product of lists. In the pursuit of making it as interactive as possible, the parsing function ended up taking the most space. The product set expression must be supplied enclosed by double quotes. Prints out usage on incorrect invocation.
Recursive implementation for computing the Cartesian product of lists. In the pursuit of making it as interactive as possible, the parsing function ended up taking the most space. The product set expression must be supplied enclosed by double quotes. Prints out usage on incorrect invocation.
<syntaxhighlight lang="c">
<lang C>
#include<string.h>
#include<string.h>
#include<stdlib.h>
#include<stdlib.h>
Line 499: Line 1,214:
return 0;
return 0;
}
}
</syntaxhighlight>
</lang>
Invocation and output :
Invocation and output :
<pre>
<pre>
Line 524: Line 1,239:
{}
{}
</pre>
</pre>
=={{header|C sharp|C#}}==

<syntaxhighlight lang="csharp">using System;
=={{header|C sharp}}==
<lang csharp>using System;
public class Program
public class Program
{
{
Line 569: Line 1,283:
select acc.Concat(new [] { item }));
select acc.Concat(new [] { item }));
}
}
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 580: Line 1,294:
{}</pre>
{}</pre>
If the number of lists is known, LINQ provides an easier solution:
If the number of lists is known, LINQ provides an easier solution:
<lang csharp>public static void Main()
<syntaxhighlight lang="csharp">public static void Main()
{
{
///...
///...
Line 595: Line 1,309:
select (a, b, c);
select (a, b, c);
Console.WriteLine($"{{{string.Join(", ", cart2)}}}");
Console.WriteLine($"{{{string.Join(", ", cart2)}}}");
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 601: Line 1,315:
{(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)}
{(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)}
</pre>
</pre>

=={{header|C++}}==
=={{header|C++}}==
<lang cpp>
<syntaxhighlight lang="cpp">
#include <iostream>
#include <iostream>
#include <vector>
#include <vector>
Line 659: Line 1,372:
std::cin.get();
std::cin.get();
return 0;
return 0;
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 669: Line 1,382:
{ (1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100) }
{ (1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100) }
{ }</pre>
{ }</pre>

=={{header|Clojure}}==
=={{header|Clojure}}==
<syntaxhighlight lang="clojure">
<lang Clojure>
(ns clojure.examples.product
(ns clojure.examples.product
(:gen-class)
(:gen-class)
Line 683: Line 1,395:
x (first colls)]
x (first colls)]
(cons x more))))
(cons x more))))
</syntaxhighlight>
</lang>
'''Output'''
'''Output'''
<lang clojure>
<syntaxhighlight lang="clojure">
(doseq [lst [ [[1,2],[3,4]],
(doseq [lst [ [[1,2],[3,4]],
[[3,4],[1,2]], [[], [1, 2]],
[[3,4],[1,2]], [[], [1, 2]],
Line 696: Line 1,408:
(println lst "=>")
(println lst "=>")
(pp/pprint (cart lst)))
(pp/pprint (cart lst)))
</syntaxhighlight>
</lang>


<pre>
<pre>
Line 737: Line 1,449:
()
()
</pre>
</pre>

=={{header|Common Lisp}}==
=={{header|Common Lisp}}==
<lang lisp>(defun cartesian-product (s1 s2)
<syntaxhighlight lang="lisp">(defun cartesian-product (s1 s2)
"Compute the cartesian product of two sets represented as lists"
"Compute the cartesian product of two sets represented as lists"
(loop for x in s1
(loop for x in s1
nconc (loop for y in s2 collect (list x y))))
nconc (loop for y in s2 collect (list x y))))
</syntaxhighlight>
</lang>


'''Output'''
'''Output'''


<lang lisp>
<syntaxhighlight lang="lisp">
CL-USER> (cartesian-product '(1 2) '(3 4))
CL-USER> (cartesian-product '(1 2) '(3 4))
((1 3) (1 4) (2 3) (2 4))
((1 3) (1 4) (2 3) (2 4))
Line 756: Line 1,467:
CL-USER> (cartesian-product '() '(1 2))
CL-USER> (cartesian-product '() '(1 2))
NIL
NIL
</syntaxhighlight>
</lang>


'''Extra credit:'''
'''Extra credit:'''


<lang lisp>(defun n-cartesian-product (l)
<syntaxhighlight lang="lisp">(defun n-cartesian-product (l)
"Compute the n-cartesian product of a list of sets (each of them represented as list).
"Compute the n-cartesian product of a list of sets (each of them represented as list).
Algorithm:
Algorithm:
Line 770: Line 1,481:
(loop for x in (car l)
(loop for x in (car l)
nconc (loop for y in (n-cartesian-product (cdr l))
nconc (loop for y in (n-cartesian-product (cdr l))
collect (cons x y)))))</lang>
collect (cons x y)))))</syntaxhighlight>


'''Output:'''
'''Output:'''


<lang lisp>CL-USER> (n-cartesian-product '((1776 1789) (7 12) (4 14 23) (0 1)))
<syntaxhighlight lang="lisp">CL-USER> (n-cartesian-product '((1776 1789) (7 12) (4 14 23) (0 1)))
((1776 7 4 0) (1776 7 4 1) (1776 7 14 0) (1776 7 14 1) (1776 7 23 0) (1776 7 23 1) (1776 12 4 0) (1776 12 4 1) (1776 12 14 0) (1776 12 14 1) (1776 12 23 0) (1776 12 23 1) (1789 7 4 0) (1789 7 4 1) (1789 7 14 0) (1789 7 14 1) (1789 7 23 0) (1789 7 23 1) (1789 12 4 0) (1789 12 4 1) (1789 12 14 0) (1789 12 14 1) (1789 12 23 0) (1789 12 23 1))
((1776 7 4 0) (1776 7 4 1) (1776 7 14 0) (1776 7 14 1) (1776 7 23 0) (1776 7 23 1) (1776 12 4 0) (1776 12 4 1) (1776 12 14 0) (1776 12 14 1) (1776 12 23 0) (1776 12 23 1) (1789 7 4 0) (1789 7 4 1) (1789 7 14 0) (1789 7 14 1) (1789 7 23 0) (1789 7 23 1) (1789 12 4 0) (1789 12 4 1) (1789 12 14 0) (1789 12 14 1) (1789 12 23 0) (1789 12 23 1))
CL-USER> (n-cartesian-product '((1 2 3) (30) (500 100)))
CL-USER> (n-cartesian-product '((1 2 3) (30) (500 100)))
Line 780: Line 1,491:
CL-USER> (n-cartesian-product '((1 2 3) () (500 100)))
CL-USER> (n-cartesian-product '((1 2 3) () (500 100)))
NIL
NIL
</syntaxhighlight>
</lang>

=={{header|Crystal}}==
=={{header|Crystal}}==
The first function is the basic task. The version overloaded for one argument is the extra credit task, implemented using recursion.
The first function is the basic task. The version overloaded for one argument is the extra credit task, implemented using recursion.
<lang crystal>def cartesian_product(a, b)
<syntaxhighlight lang="crystal">def cartesian_product(a, b)
return a.flat_map { |i| b.map { |j| [i, j] } }
return a.flat_map { |i| b.map { |j| [i, j] } }
end
end
Line 817: Line 1,527:
puts ""
puts ""
}
}
</syntaxhighlight>
</lang>


{{out}}
{{out}}
Line 841: Line 1,551:
[[1776, 7, 4, 0], [1776, 7, 4, 1], [1776, 7, 14, 0], [1776, 7, 14, 1], [1776, 7, 23, 0], [1776, 7, 23, 1], [1776, 12, 4, 0], [1776, 12, 4, 1], [1776, 12, 14, 0], [1776, 12, 14, 1], [1776, 12, 23, 0], [1776, 12, 23, 1], [1789, 7, 4, 0], [1789, 7, 4, 1], [1789, 7, 14, 0], [1789, 7, 14, 1], [1789, 7, 23, 0], [1789, 7, 23, 1], [1789, 12, 4, 0], [1789, 12, 4, 1], [1789, 12, 14, 0], [1789, 12, 14, 1], [1789, 12, 23, 0], [1789, 12, 23, 1]]
[[1776, 7, 4, 0], [1776, 7, 4, 1], [1776, 7, 14, 0], [1776, 7, 14, 1], [1776, 7, 23, 0], [1776, 7, 23, 1], [1776, 12, 4, 0], [1776, 12, 4, 1], [1776, 12, 14, 0], [1776, 12, 14, 1], [1776, 12, 23, 0], [1776, 12, 23, 1], [1789, 7, 4, 0], [1789, 7, 4, 1], [1789, 7, 14, 0], [1789, 7, 14, 1], [1789, 7, 23, 0], [1789, 7, 23, 1], [1789, 12, 4, 0], [1789, 12, 4, 1], [1789, 12, 14, 0], [1789, 12, 14, 1], [1789, 12, 23, 0], [1789, 12, 23, 1]]
</pre>
</pre>

=={{header|D}}==
=={{header|D}}==
<lang D>import std.stdio;
<syntaxhighlight lang="d">import std.stdio;


void main() {
void main() {
Line 881: Line 1,590:


return Result();
return Result();
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 888: Line 1,597:
[]
[]
[]</pre>
[]</pre>
=={{header|Delphi}}==
{{libheader| System.SysUtils}}
{{Trans|Go}}
<syntaxhighlight lang="delphi">
program Cartesian_product_of_two_or_more_lists;

{$APPTYPE CONSOLE}

uses
System.SysUtils;

type
TList = TArray<Integer>;

TLists = TArray<TList>;

TListHelper = record helper for TList
function ToString: string;
end;

TListsHelper = record helper for TLists
function ToString(BreakLines: boolean = false): string;
end;

function cartN(arg: TLists): TLists;
var
b, n: TList;
argc: Integer;
begin
argc := length(arg);

var c := 1;
for var a in arg do
c := c * length(a);

if c = 0 then
exit;

SetLength(result, c);
SetLength(b, c * argc);
SetLength(n, argc);

var s := 0;
for var i := 0 to c - 1 do
begin
var e := s + argc;
var Resi := copy(b, s, e - s);
Result[i] := Resi;

s := e;
for var j := 0 to high(n) do
begin
var nj := n[j];
Resi[j] := arg[j, nj];
end;

for var j := high(n) downto 0 do
begin
inc(n[j]);
if n[j] < Length(arg[j]) then
Break;
n[j] := 0;
end;
end;
end;

{ TListHelper }

function TListHelper.ToString: string;
begin
Result := '[';
for var i := 0 to High(self) do
begin
Result := Result + self[i].ToString;
if i < High(self) then
Result := Result + ' ';
end;
Result := Result + ']';
end;

{ TListsHelper }

function TListsHelper.ToString(BreakLines: boolean = false): string;
begin
Result := '[';
for var i := 0 to High(self) do
begin
Result := Result + self[i].ToString;
if i < High(self) then
begin
if BreakLines then
Result := Result + #10
else
Result := Result + ' ';
end;
end;
Result := Result + ']';
end;

begin
writeln(#10, cartN([[1, 2], [3, 4]]).ToString);
writeln(#10, cartN([[3, 4], [1, 2]]).ToString);
writeln(#10, cartN([[1, 2], []]).ToString);
writeln(#10, cartN([[], [1, 2]]).ToString);

writeln(#10, cartN([[1776, 1789], [17, 12], [4, 14, 23], [0, 1]]).ToString(True));

writeln(#10, cartN([[1, 2, 3], [30], [500, 100]]).ToString);

writeln(#10, cartN([[1, 2, 3], [], [500, 100]]).ToString);

{$IFNDEF UNIX} readln; {$ENDIF}
end.</syntaxhighlight>
{{out}}
<pre>[[1 3] [1 4] [2 3] [2 4]]

[[3 1] [3 2] [4 1] [4 2]]

[]

[]

[[1776 17 4 0]
[1776 17 4 1]
[1776 17 14 0]
[1776 17 14 1]
[1776 17 23 0]
[1776 17 23 1]
[1776 12 4 0]
[1776 12 4 1]
[1776 12 14 0]
[1776 12 14 1]
[1776 12 23 0]
[1776 12 23 1]
[1789 17 4 0]
[1789 17 4 1]
[1789 17 14 0]
[1789 17 14 1]
[1789 17 23 0]
[1789 17 23 1]
[1789 12 4 0]
[1789 12 4 1]
[1789 12 14 0]
[1789 12 14 1]
[1789 12 23 0]
[1789 12 23 1]]

[[1 30 500] [1 30 100] [2 30 500] [2 30 100] [3 30 500] [3 30 100]]

[]</pre>
=={{header|EasyLang}}==
{{trans|Go}}
<syntaxhighlight>
proc cart2 a[] b[] . p[][] .
p[][] = [ ]
for a in a[]
for b in b[]
p[][] &= [ a b ]
.
.
.
cart2 [ 1 2 ] [ 3 4 ] r[][]
print r[][]
cart2 [ 3 4 ] [ 1 2 ] r[][]
print r[][]
cart2 [ 1 2 ] [ ] r[][]
print r[][]
cart2 [ ] [ 1 2 ] r[][]
print r[][]
</syntaxhighlight>

=={{header|Erlang}}==
Can do this with list comprehensions.
<syntaxhighlight lang="erlang">
-module(cartesian).
-export([product/2]).

product(S1, S2) -> [{A,B} || A <- S1, B <- S2].
</syntaxhighlight>
{{Out}}
<pre>
2> cartesian:product([],[1,2,3]).
[]
3> cartesian:product([1,2,3],[]).
[]
4> cartesian:product([1,2],[3,4]).
[{1,3},{1,4},{2,3},{2,4}]
5> cartesian:product([3,4],[1,2]).
[{3,1},{3,2},{4,1},{4,2}]
</pre>


=={{header|F Sharp|F#}}==
=={{header|F Sharp|F#}}==
===The Task===
===The Task===
<lang fsharp>
<syntaxhighlight lang="fsharp">
//Nigel Galloway February 12th., 2018
//Nigel Galloway February 12th., 2018
let cP2 n g = List.map (fun (n,g)->[n;g]) (List.allPairs n g)
let cP2 n g = List.map (fun (n,g)->[n;g]) (List.allPairs n g)
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 904: Line 1,803:


===Extra Credit===
===Extra Credit===
<lang fsharp>
<syntaxhighlight lang="fsharp">
//Nigel Galloway August 14th., 2018
//Nigel Galloway August 14th., 2018
let cP ng=Seq.foldBack(fun n g->[for n' in n do for g' in g do yield n'::g']) ng [[]]
let cP ng=Seq.foldBack(fun n g->[for n' in n do for g' in g do yield n'::g']) ng [[]]
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 925: Line 1,824:


=={{header|Factor}}==
=={{header|Factor}}==
<lang Factor>IN: scratchpad { 1 2 } { 3 4 } cartesian-product .
<syntaxhighlight lang="factor">IN: scratchpad { 1 2 } { 3 4 } cartesian-product .
{ { { 1 3 } { 1 4 } } { { 2 3 } { 2 4 } } }
{ { { 1 3 } { 1 4 } } { { 2 3 } { 2 4 } } }
IN: scratchpad { 3 4 } { 1 2 } cartesian-product .
IN: scratchpad { 3 4 } { 1 2 } cartesian-product .
Line 932: Line 1,831:
{ { } { } }
{ { } { } }
IN: scratchpad { } { 1 2 } cartesian-product .
IN: scratchpad { } { 1 2 } cartesian-product .
{ }</lang>
{ }</syntaxhighlight>
=={{header|Fortran}}==
This implementation is hard to extend to n-ary products but it is simple and works well for binary products of lists of any length.

<syntaxhighlight lang="fortran">
! Created by simon on 29/04/2021.
! ifort -o cartesian_product cartesian_product.f90 -check all
module tuple
implicit none
private
public :: tuple_t, operator(*), print
type tuple_t(n)
integer, len :: n
integer, private :: v(n)
contains
procedure, public :: print => print_tuple_t
generic, public :: assignment(=) => eq_tuple_t
procedure, public :: eq_tuple_t
end type tuple_t
interface print
module procedure print_tuple_a_t
end interface print
interface operator(*)
module procedure tup_times_tup
end interface
contains
subroutine eq_tuple_t(this, src)
class(tuple_t(*)), intent(inout) :: this
integer, intent(in) :: src(:)
this%v = src
end subroutine eq_tuple_t

pure function tup_times_tup(a, b) result(r)
type(tuple_t(*)), intent(in) :: a
type(tuple_t(*)), intent(in) :: b
type(tuple_t(2)), allocatable :: r(:)
integer :: i, j, k
allocate(r(a%n*b%n))
k = 0
do i=1,a%n
do j=1,b%n
k = k + 1
r(k)%v = [a%v(i),b%v(j)]
end do
end do
end function tup_times_tup
subroutine print_tuple_t(this)
class(tuple_t(*)), intent(in) :: this
integer :: i
write(*,fmt='(a)',advance='no') '{'
do i=1,size(this%v)
write(*,fmt='(i0)',advance='no') this%v(i)
if (i < size(this%v)) write(*,fmt='(a)',advance='no') ','
end do
write(*,fmt='(a)',advance='no') '}'
end subroutine print_tuple_t
subroutine print_tuple_a_t(r)
type(tuple_t(*)), intent(in) :: r(:)
integer :: i
write(*,fmt='(a)',advance='no') '{'
do i=1,size(r)
call r(i)%print
if (i < size(r)) write(*,fmt='(a)',advance='no') ','
end do
write(*,fmt='(a)') '}'
end subroutine print_tuple_a_t
end module tuple
program cartesian_product
use tuple
implicit none
type(tuple_t(2)) :: a, b
type(tuple_t(0)) :: z
a = [1,2]
b = [3,4]
call print_product(a, b)
call print_product(b, a)
call print_product(z, a)
call print_product(a, z)
stop
contains
subroutine print_product(s, t)
type(tuple_t(*)), intent(in) :: s
type(tuple_t(*)), intent(in) :: t
call s%print
write(*,fmt='(a)',advance='no') ' x '
call t%print
write(*,fmt='(a)',advance='no') ' = '
call print(s*t)
end subroutine print_product
end program cartesian_product
</syntaxhighlight>
{{out}}
<pre> {1,2} x {3,4} = {{1,3},{1,4},{2,3},{2,4}}
{3,4} x {1,2} = {{3,1},{3,2},{4,1},{4,2}}
{1,2} x {} = {}
{} x {1,2} = {}</pre>


=={{header|FreeBASIC}}==
=={{header|FreeBASIC}}==
I'll leave the extra credit part for someone else. It's just going to amount to repeatedly finding Cartesian products and [[Flatten a list|flattening]] the result, so considerably less interesting than Cartesian products where the list items themselves can be lists.
I'll leave the extra credit part for someone else. It's just going to amount to repeatedly finding Cartesian products and [[Flatten a list|flattening]] the result, so considerably less interesting than Cartesian products where the list items themselves can be lists.


<lang freebasic>#define MAXLEN 64
<syntaxhighlight lang="freebasic">#define MAXLEN 64


type listitem ' An item of a list may be a number
type listitem ' An item of a list may be a number
Line 998: Line 2,005:
R = cartprod(B, A) : print_list(R) : print
R = cartprod(B, A) : print_list(R) : print
R = cartprod(A, EMPTY) : print_list(R) : print
R = cartprod(A, EMPTY) : print_list(R) : print
R = cartprod(EMPTY, A) : print_list(R) : print</lang>
R = cartprod(EMPTY, A) : print_list(R) : print</syntaxhighlight>
{{out}}<pre>{{1, 3}, {1, 4}, {2, 3}, {2, 4}}
{{out}}<pre>{{1, 3}, {1, 4}, {2, 3}, {2, 4}}
{{3, 1}, {3, 2}, {4, 1}, {4, 2}}
{{3, 1}, {3, 2}, {4, 1}, {4, 2}}
Line 1,007: Line 2,014:
=={{header|Fōrmulæ}}==
=={{header|Fōrmulæ}}==


In [http://wiki.formulae.org/Cartesian_product_of_two_or_more_lists this] page you can see the solution of this task.
{{FormulaeEntry|page=https://formulae.org/?script=examples/Cartesian_product_of_two_or_more_lists}}


'''Solution'''
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text ([http://wiki.formulae.org/Editing_F%C5%8Drmul%C3%A6_expressions more info]). Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation &mdash;i.e. XML, JSON&mdash; they are intended for transportation effects more than visualization and edition.


No program is needed, the cartesian product is an intrinsic operation in Fōrmulæ
The option to show Fōrmulæ programs and their results is showing images. Unfortunately images cannot be uploaded in Rosetta Code.

'''Test case 1.''' No commutativity

[[File:Fōrmulæ - Cartesian product of two or more lists 01.png]]

[[File:Fōrmulæ - Cartesian product of two or more lists 02.png]]

[[File:Fōrmulæ - Cartesian product of two or more lists 03.png]]

[[File:Fōrmulæ - Cartesian product of two or more lists 04.png]]

'''Test case 2.''' With an empty list

[[File:Fōrmulæ - Cartesian product of two or more lists 05.png]]

[[File:Fōrmulæ - Empty list.png]]

[[File:Fōrmulæ - Cartesian product of two or more lists 06.png]]

[[File:Fōrmulæ - Empty list.png]]

'''Test case 3.''' Extra credit. n-ary cartesian product

[[File:Fōrmulæ - Cartesian product of two or more lists 07.png]]

[[File:Fōrmulæ - Cartesian product of two or more lists 08.png]]

[[File:Fōrmulæ - Cartesian product of two or more lists 09.png]]

[[File:Fōrmulæ - Cartesian product of two or more lists 10.png]]

[[File:Fōrmulæ - Cartesian product of two or more lists 11.png]]

[[File:Fōrmulæ - Empty list.png]]


=={{header|Go}}==
=={{header|Go}}==
'''Basic Task'''
'''Basic Task'''
<lang go>package main
<syntaxhighlight lang="go">package main


import "fmt"
import "fmt"
Line 1,038: Line 2,079:
fmt.Println(cart2([]int{1, 2}, nil))
fmt.Println(cart2([]int{1, 2}, nil))
fmt.Println(cart2(nil, []int{1, 2}))
fmt.Println(cart2(nil, []int{1, 2}))
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 1,049: Line 2,090:


This solution minimizes allocations and computes and fills the result sequentially.
This solution minimizes allocations and computes and fills the result sequentially.
<lang go>package main
<syntaxhighlight lang="go">package main


import "fmt"
import "fmt"
Line 1,107: Line 2,148:
fmt.Println(cartN(nil))
fmt.Println(cartN(nil))
fmt.Println(cartN())
fmt.Println(cartN())
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 1,150: Line 2,191:


Code here is more compact, but with the cost of more garbage produced. It produces the same result as cartN above.
Code here is more compact, but with the cost of more garbage produced. It produces the same result as cartN above.
<lang go>func cartN(a ...[]int) (c [][]int) {
<syntaxhighlight lang="go">func cartN(a ...[]int) (c [][]int) {
if len(a) == 0 {
if len(a) == 0 {
return [][]int{nil}
return [][]int{nil}
Line 1,161: Line 2,202:
}
}
return
return
}</lang>
}</syntaxhighlight>
'''Extra credit 3'''
'''Extra credit 3'''


This is a compact recursive version like Extra credit 2 but the result list is ordered differently. This is still a correct result if you consider a cartesian product to be a set, which is an unordered collection. Note that the set elements are still ordered lists. A cartesian product is an unordered collection of ordered collections. It draws attention though to the gloss of using list representations as sets. Any of the functions here will accept duplicate elements in the input lists, and then produce duplicate elements in the result.
This is a compact recursive version like Extra credit 2 but the result list is ordered differently. This is still a correct result if you consider a cartesian product to be a set, which is an unordered collection. Note that the set elements are still ordered lists. A cartesian product is an unordered collection of ordered collections. It draws attention though to the gloss of using list representations as sets. Any of the functions here will accept duplicate elements in the input lists, and then produce duplicate elements in the result.
<lang go>func cartN(a ...[]int) (c [][]int) {
<syntaxhighlight lang="go">func cartN(a ...[]int) (c [][]int) {
if len(a) == 0 {
if len(a) == 0 {
return [][]int{nil}
return [][]int{nil}
Line 1,177: Line 2,218:
}
}
return
return
}</lang>
}</syntaxhighlight>

=={{header|Groovy}}==
=={{header|Groovy}}==
'''Solution:'''<br>
'''Solution:'''<br>
The following ''CartesianCategory'' class allows for modification of regular ''Iterable'' interface behavior, overloading ''Iterable'''s ''multiply'' (*) operator to perform a Cartesian Product when the second operand is also an ''Iterable''.
The following ''CartesianCategory'' class allows for modification of regular ''Iterable'' interface behavior, overloading ''Iterable'''s ''multiply'' (*) operator to perform a Cartesian Product when the second operand is also an ''Iterable''.
<lang groovy>class CartesianCategory {
<syntaxhighlight lang="groovy">class CartesianCategory {
static Iterable multiply(Iterable a, Iterable b) {
static Iterable multiply(Iterable a, Iterable b) {
assert [a,b].every { it != null }
assert [a,b].every { it != null }
Line 1,188: Line 2,228:
(0..<(m*n)).inject([]) { prod, i -> prod << [a[i.intdiv(n)], b[i%n]].flatten() }
(0..<(m*n)).inject([]) { prod, i -> prod << [a[i.intdiv(n)], b[i%n]].flatten() }
}
}
}</lang>
}</syntaxhighlight>
'''Test:'''<br>
'''Test:'''<br>
The ''mixin'' method call is necessary to make the multiply (*) operator work.
The ''mixin'' method call is necessary to make the multiply (*) operator work.
<lang groovy>Iterable.metaClass.mixin CartesianCategory
<syntaxhighlight lang="groovy">Iterable.metaClass.mixin CartesianCategory


println "\nCore Solution:"
println "\nCore Solution:"
Line 1,207: Line 2,247:
println "[John,Paul,George,Ringo] × [Emerson,Lake,Palmer] × [Simon,Garfunkle] = ["
println "[John,Paul,George,Ringo] × [Emerson,Lake,Palmer] × [Simon,Garfunkle] = ["
( ["John","Paul","George","Ringo"] * ["Emerson","Lake","Palmer"] * ["Simon","Garfunkle"] ).each { println "\t${it}," }
( ["John","Paul","George","Ringo"] * ["Emerson","Lake","Palmer"] * ["Simon","Garfunkle"] ).each { println "\t${it}," }
println "]"</lang>
println "]"</syntaxhighlight>
'''Output:'''
'''Output:'''
<pre>
<pre>
Line 1,248: Line 2,288:
[Ringo, Palmer, Garfunkle],
[Ringo, Palmer, Garfunkle],
]</pre>
]</pre>

=={{header|Haskell}}==
=={{header|Haskell}}==
Various routes can be taken to Cartesian products in Haskell.
Various routes can be taken to Cartesian products in Haskell.
For the product of two lists we could write:
For the product of two lists we could write:
<lang Haskell>cartProd :: [a] -> [b] -> [(a, b)]
<syntaxhighlight lang="haskell">cartProd :: [a] -> [b] -> [(a, b)]
cartProd xs ys =
cartProd xs ys =
[ (x, y)
[ (x, y)
| x <- xs
| x <- xs
, y <- ys ]</lang>
, y <- ys ]</syntaxhighlight>


more directly:
more directly:
<lang Haskell>cartProd :: [a] -> [b] -> [(a, b)]
<syntaxhighlight lang="haskell">cartProd :: [a] -> [b] -> [(a, b)]
cartProd xs ys = xs >>= \x -> ys >>= \y -> [(x, y)]</lang>
cartProd xs ys = xs >>= \x -> ys >>= \y -> [(x, y)]</syntaxhighlight>


applicatively:
applicatively:
<lang Haskell>cartProd :: [a] -> [b] -> [(a, b)]
<syntaxhighlight lang="haskell">cartProd :: [a] -> [b] -> [(a, b)]
cartProd xs ys = (,) <$> xs <*> ys</lang>
cartProd xs ys = (,) <$> xs <*> ys</syntaxhighlight>


parsimoniously:
parsimoniously:
<lang Haskell>cartProd :: [a] -> [b] -> [(a, b)]
<syntaxhighlight lang="haskell">cartProd :: [a] -> [b] -> [(a, b)]
cartProd = (<*>) . fmap (,)</lang>
cartProd = (<*>) . fmap (,)</syntaxhighlight>


We might test any of these with:
We might test any of these with:
<lang haskell>main :: IO ()
<syntaxhighlight lang="haskell">main :: IO ()
main =
main =
mapM_ print $
mapM_ print $
uncurry cartProd <$>
uncurry cartProd <$>
[([1, 2], [3, 4]), ([3, 4], [1, 2]), ([1, 2], []), ([], [1, 2])]</lang>
[([1, 2], [3, 4]), ([3, 4], [1, 2]), ([1, 2], []), ([], [1, 2])]</syntaxhighlight>
{{Out}}
{{Out}}
<pre>[(1,3),(1,4),(2,3),(2,4)]
<pre>[(1,3),(1,4),(2,3),(2,4)]
Line 1,284: Line 2,323:


For the n-ary Cartesian product of an arbitrary number of lists, we could apply the Prelude's standard '''sequence''' function to a list of lists,
For the n-ary Cartesian product of an arbitrary number of lists, we could apply the Prelude's standard '''sequence''' function to a list of lists,
<lang haskell>cartProdN :: [[a]] -> [[a]]
<syntaxhighlight lang="haskell">cartProdN :: [[a]] -> [[a]]
cartProdN = sequence
cartProdN = sequence


main :: IO ()
main :: IO ()
main = print $ cartProdN [[1, 2], [3, 4], [5, 6]]</lang>
main = print $ cartProdN [[1, 2], [3, 4], [5, 6]]</syntaxhighlight>
{{Out}}
{{Out}}
<pre>[[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]]</pre>
<pre>[[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]]</pre>


or we could define ourselves an equivalent function over a list of lists in terms of a fold, for example as:
or we could define ourselves an equivalent function over a list of lists in terms of a fold, for example as:
<lang haskell>cartProdN :: [[a]] -> [[a]]
<syntaxhighlight lang="haskell">cartProdN :: [[a]] -> [[a]]
cartProdN = foldr (\xs as -> xs >>= (<$> as) . (:)) [[]]</lang>
cartProdN = foldr (\xs as -> xs >>= (<$> as) . (:)) [[]]</syntaxhighlight>
or, equivalently, as:
or, equivalently, as:
<lang haskell>cartProdN :: [[a]] -> [[a]]
<syntaxhighlight lang="haskell">cartProdN :: [[a]] -> [[a]]
cartProdN = foldr
cartProdN = foldr
(\xs as ->
(\xs as ->
Line 1,302: Line 2,341:
| x <- xs
| x <- xs
, a <- as ])
, a <- as ])
[[]]</lang>
[[]]</syntaxhighlight>
testing any of these with something like:
testing any of these with something like:
<lang haskell>main :: IO ()
<syntaxhighlight lang="haskell">main :: IO ()
main = do
main = do
mapM_ print $
mapM_ print $
Line 1,311: Line 2,350:
print $ cartProdN [[1,2,3], [30], [500, 100]]
print $ cartProdN [[1,2,3], [30], [500, 100]]
putStrLn ""
putStrLn ""
print $ cartProdN [[1,2,3], [], [500, 100]]</lang>
print $ cartProdN [[1,2,3], [], [500, 100]]</syntaxhighlight>
{{Out}}
{{Out}}
<pre>[1776,7,4,0]
<pre>[1776,7,4,0]
Line 1,341: Line 2,380:


[]</pre>
[]</pre>

=={{header|J}}==
=={{header|J}}==
The J primitive [http://code.jsoftware.com/wiki/Vocabulary/curlylf catalogue] <code>{</code> forms the Cartesian Product of two or more boxed lists. The result is a multi-dimensional array (which can be reshaped to a simple list of lists if desired).
The J primitive [http://code.jsoftware.com/wiki/Vocabulary/curlylf catalogue] <code>{</code> forms the Cartesian Product of two or more boxed lists. The result is a multi-dimensional array (which can be reshaped to a simple list of lists if desired).
<lang j> { 1776 1789 ; 7 12 ; 4 14 23 ; 0 1 NB. result is 4 dimensional array with shape 2 2 3 2
<syntaxhighlight lang="j"> { 1776 1789 ; 7 12 ; 4 14 23 ; 0 1 NB. result is 4 dimensional array with shape 2 2 3 2
┌────────────┬────────────┐
┌────────────┬────────────┐
│1776 7 4 0 │1776 7 4 1 │
│1776 7 4 0 │1776 7 4 1 │
Line 1,386: Line 2,424:
└───────┴────────┘
└───────┴────────┘
{ 1 2 3 ; '' ; 50 100 NB. result is an empty 3-dimensional array with shape 3 0 2
{ 1 2 3 ; '' ; 50 100 NB. result is an empty 3-dimensional array with shape 3 0 2
</syntaxhighlight>
</lang>

=={{header|Java}}==
=={{header|Java}}==
{{works with|Java Virtual Machine|1.8}}
{{works with|Java Virtual Machine|1.8}}
<syntaxhighlight lang="java">
<lang Java>
import static java.util.Arrays.asList;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyList;
Line 1,419: Line 2,456:
}
}
}
}
</syntaxhighlight>
</lang>


'''Using a generic class with a recursive function'''
'''Using a generic class with a recursive function'''
<syntaxhighlight lang="java">
<lang Java>
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
Line 1,478: Line 2,515:
}
}
}
}
</syntaxhighlight>
</lang>

=={{header|JavaScript}}==
=={{header|JavaScript}}==
function cartesian(m){
if(!m.length)return[[]];
let tails=cartesian(m.slice(1));
return(m[0].flatMap(h=>tails.map(t=>[h].concat(t))));
}

===ES6===
===ES6===
====Functional====
====Functional====
Line 1,486: Line 2,528:


For the Cartesian product of just two lists:
For the Cartesian product of just two lists:
<lang JavaScript>(() => {
<syntaxhighlight lang="javascript">(() => {
// CARTESIAN PRODUCT OF TWO LISTS ---------------------
// CARTESIAN PRODUCT OF TWO LISTS ---------------------


Line 1,501: Line 2,543:
cartProd([])([1, 2]),
cartProd([])([1, 2]),
].map(JSON.stringify).join('\n');
].map(JSON.stringify).join('\n');
})();</lang>
})();</syntaxhighlight>
{{Out}}
{{Out}}
<pre>[[1,3],[1,4],[2,3],[2,4]]
<pre>[[1,3],[1,4],[2,3],[2,4]]
Line 1,510: Line 2,552:


Abstracting a little more, we can define the cartesian product quite economically in terms of a general applicative operator:
Abstracting a little more, we can define the cartesian product quite economically in terms of a general applicative operator:
<lang Javascript>(() => {
<syntaxhighlight lang="javascript">(() => {


// CARTESIAN PRODUCT OF TWO LISTS ---------------------
// CARTESIAN PRODUCT OF TWO LISTS ---------------------
Line 1,548: Line 2,590:
.map(JSON.stringify)
.map(JSON.stringify)
.join('\n');
.join('\n');
})();</lang>
})();</syntaxhighlight>
{{Out}}
{{Out}}
<pre>[[1,3],[1,4],[2,3],[2,4]]
<pre>[[1,3],[1,4],[2,3],[2,4]]
Line 1,556: Line 2,598:


For the n-ary Cartesian product over a list of lists:
For the n-ary Cartesian product over a list of lists:
<lang JavaScript>(() => {
<syntaxhighlight lang="javascript">(() => {
const main = () => {
const main = () => {
// n-ary Cartesian product of a list of lists.
// n-ary Cartesian product of a list of lists.
Line 1,616: Line 2,658:


return main();
return main();
})();</lang>
})();</syntaxhighlight>
{{Out}}
{{Out}}
<pre>[1776,7,4,0]
<pre>[1776,7,4,0]
Line 1,650: Line 2,692:
Imperative implementations of Cartesian products are inevitably less compact and direct, but we can certainly write an iterative translation of a fold over nested applications of '''bind''' or '''concatMap''':
Imperative implementations of Cartesian products are inevitably less compact and direct, but we can certainly write an iterative translation of a fold over nested applications of '''bind''' or '''concatMap''':


<lang JavaScript>(() => {
<syntaxhighlight lang="javascript">(() => {
// n-ary Cartesian product of a list of lists
// n-ary Cartesian product of a list of lists
// ( Imperative implementation )
// ( Imperative implementation )
Line 1,723: Line 2,765:
]))
]))
]);
]);
})();</lang>
})();</syntaxhighlight>
{{Out}}
{{Out}}
<pre>[[1,4],[1,3],[2,4],[2,3]]
<pre>[[1,4],[1,3],[2,4],[2,3]]
Line 1,765: Line 2,807:


jq is stream-oriented and so we begin by defining a function that will emit a stream of the elements of the Cartesian product of two arrays:
jq is stream-oriented and so we begin by defining a function that will emit a stream of the elements of the Cartesian product of two arrays:
<syntaxhighlight lang="jq">
<lang jq>
def products: .[0][] as $x | .[1][] as $y | [$x,$y];
def products: .[0][] as $x | .[1][] as $y | [$x,$y];
</syntaxhighlight>
</lang>


To generate an array of these arrays, one would in practice most likely simply write `[products]`, but to comply with the requirements of this article, we can define `product` as:
To generate an array of these arrays, one would in practice most likely simply write `[products]`, but to comply with the requirements of this article, we can define `product` as:
<syntaxhighlight lang="jq">
<lang jq>
def product: [products];
def product: [products];
</syntaxhighlight>
</lang>


For the sake of brevity, two illustrations should suffice:
For the sake of brevity, two illustrations should suffice:
Line 1,787: Line 2,829:


And
And
<syntaxhighlight lang="jq">
<lang jq>
[[1,2], []] | product
[[1,2], []] | product
</syntaxhighlight>
</lang>
produces:
produces:
<pre>
<pre>
Line 1,798: Line 2,840:
Given an array of two or more arrays as input, `cartesians` as defined here produces a stream of the components of their Cartesian product:
Given an array of two or more arrays as input, `cartesians` as defined here produces a stream of the components of their Cartesian product:


<syntaxhighlight lang="jq">
<lang jq>
def cartesians:
def cartesians:
if length <= 2 then products
if length <= 2 then products
Line 1,805: Line 2,847:
| [$x] + $y
| [$x] + $y
end;
end;
</syntaxhighlight>
</lang>


Again for brevity, in the following, we will just show the number of items in the Cartesian products:
Again for brevity, in the following, we will just show the number of items in the Cartesian products:
Line 1,817: Line 2,859:
[[1, 2, 3], [], [500, 100] ] | [cartesians] | length
[[1, 2, 3], [], [500, 100] ] | [cartesians] | length
# 0
# 0

=={{header|Julia}}==
=={{header|Julia}}==
Run in REPL.
Run in REPL.
<lang julia>
<syntaxhighlight lang="julia">
# Product {1, 2} × {3, 4}
# Product {1, 2} × {3, 4}
collect(Iterators.product([1, 2], [3, 4]))
collect(Iterators.product([1, 2], [3, 4]))
Line 1,837: Line 2,878:
# Product {1, 2, 3} × {} × {500, 100}
# Product {1, 2, 3} × {} × {500, 100}
collect(Iterators.product([1, 2, 3], [], [500, 100]))
collect(Iterators.product([1, 2, 3], [], [500, 100]))
</syntaxhighlight>
</lang>

=={{header|Kotlin}}==
=={{header|Kotlin}}==
<lang scala>// version 1.1.2
<syntaxhighlight lang="scala">// version 1.1.2


fun flattenList(nestList: List<Any>): List<Any> {
fun flattenList(nestList: List<Any>): List<Any> {
Line 1,892: Line 2,932:
printNAryProduct(listOf(listOf(1, 2, 3), listOf<Int>(), listOf(500, 100)))
printNAryProduct(listOf(listOf(1, 2, 3), listOf<Int>(), listOf(500, 100)))
printNAryProduct(listOf(listOf(1, 2, 3), listOf(30), listOf('a', 'b')))
printNAryProduct(listOf(listOf(1, 2, 3), listOf(30), listOf('a', 'b')))
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 1,955: Line 2,995:
]
]
</pre>
</pre>

=={{header|langur}}==
=={{header|langur}}==
<syntaxhighlight lang="langur">val .X = fn(... .x) { .x }
We could use mapX() to map each set of values to a function, but this assignment only requires an array of arrays, so we use the X() function.


writeln mapX(.X, [1, 2], [3, 4]) == [[1, 3], [1, 4], [2, 3], [2, 4]]
{{works with|langur|0.8.3}}
<lang langur>writeln X([1, 2], [3, 4]) == [[1, 3], [1, 4], [2, 3], [2, 4]]
writeln mapX(.X, [3, 4], [1, 2]) == [[3, 1], [3, 2], [4, 1], [4, 2]]
writeln X([3, 4], [1, 2]) == [[3, 1], [3, 2], [4, 1], [4, 2]]
writeln mapX(.X, [1, 2], []) == []
writeln X([1, 2], []) == []
writeln mapX(.X, [], [1, 2]) == []
writeln X([], [1, 2]) == []
writeln()
writeln()


writeln X [1776, 1789], [7, 12], [4, 14, 23], [0, 1]
writeln mapX .X, [1776, 1789], [7, 12], [4, 14, 23], [0, 1]
writeln()
writeln()


writeln X [1, 2, 3], [30], [500, 100]
writeln mapX .X, [1, 2, 3], [30], [500, 100]
writeln()
writeln()


writeln X [1, 2, 3], [], [500, 100]
writeln mapX .X, [1, 2, 3], [], [500, 100]
writeln()</lang>
writeln()</syntaxhighlight>


{{out}}
{{out}}
Line 1,991: Line 3,029:
=== Functional ===
=== Functional ===
An iterator is created to output the product items.
An iterator is created to output the product items.
<lang lua> local pk,upk = table.pack, table.unpack
<syntaxhighlight lang="lua"> local pk,upk = table.pack, table.unpack
local getn = function(t)return #t end
local getn = function(t)return #t end
local const = function(k)return function(e) return k end end
local const = function(k)return function(e) return k end end
Line 2,040: Line 3,078:
print(i,a,b)
print(i,a,b)
end
end
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>1 1 3
<pre>1 1 3
Line 2,056: Line 3,094:


It is possible that specialising descend by depth may yield a further improvement in performance, but it would only be able to eliminate the lookup of ''sets[depth]'' and the if test, because the reference to ''result[depth]'' is required; I doubt the increase in complexity would be worth the (potential) improvement in performance.
It is possible that specialising descend by depth may yield a further improvement in performance, but it would only be able to eliminate the lookup of ''sets[depth]'' and the if test, because the reference to ''result[depth]'' is required; I doubt the increase in complexity would be worth the (potential) improvement in performance.
<lang lua>local function cartesian_product(sets)
<syntaxhighlight lang="lua">local function cartesian_product(sets)
local result = {}
local result = {}
local set_count = #sets
local set_count = #sets
Line 2,104: Line 3,142:
print(" " .. format_nested_list(product))
print(" " .. format_nested_list(product))
end
end
end</lang>
end</syntaxhighlight>


=== Imperative iterator ===
=== Imperative iterator ===
The functional implementation restated as an imperative iterator, also adjusted to not allocate a new result table on each iteration; this saves time, but makes mutating the returned table unsafe.
The functional implementation restated as an imperative iterator, also adjusted to not allocate a new result table on each iteration; this saves time, but makes mutating the returned table unsafe.
<lang lua>local function cartesian_product(sets)
<syntaxhighlight lang="lua">local function cartesian_product(sets)
local item_counts = {}
local item_counts = {}
local indices = {}
local indices = {}
Line 2,181: Line 3,219:
print(i, format_nested_list(product))
print(i, format_nested_list(product))
end
end
end</lang>
end</syntaxhighlight>


=== Functional-esque (non-iterator) ===
Motivation: If a list-of-lists is passed into the cartesian product, then wouldn't a list-of-lists be the expected return type? Of course this is just personal opinion/preference, other implementations are fine as-is if you'd rather have an iterator.
<syntaxhighlight lang="lua">-- support:
function T(t) return setmetatable(t, {__index=table}) end
table.clone = function(t) local s=T{} for k,v in ipairs(t) do s[k]=v end return s end
table.reduce = function(t,f,acc) for i=1,#t do acc=f(t[i],acc) end return acc end

-- implementation:
local function cartprod(sets)
local temp, prod = T{}, T{}
local function descend(depth)
for _,v in ipairs(sets[depth]) do
temp[depth] = v
if (depth==#sets) then prod[#prod+1]=temp:clone() else descend(depth+1) end
end
end
descend(1)
return prod
end

-- demonstration:
tests = {
{ {1, 2}, {3, 4} },
{ {3, 4}, {1, 2} },
{ {1, 2}, {} },
{ {}, {1, 2} },
{ {1776, 1789}, {7, 12}, {4, 14, 23}, {0, 1} },
{ {1, 2, 3}, {30}, {500, 100} },
{ {1, 2, 3}, {}, {500, 100} }
}
for _,test in ipairs(tests) do
local cp = cartprod(test)
print("{"..cp:reduce(function(t,a) return (a=="" and a or a..", ").."("..t:concat(", ")..")" end,"").."}")
end</syntaxhighlight>
{{out}}
<pre>{(1, 3), (1, 4), (2, 3), (2, 4)}
{(3, 1), (3, 2), (4, 1), (4, 2)}
{}
{}
{(1776, 7, 4, 0), (1776, 7, 4, 1), (1776, 7, 14, 0), (1776, 7, 14, 1), (1776, 7, 23, 0), (1776, 7, 23, 1), (1776, 12, 4, 0), (1776, 12, 4, 1), (1776, 12, 14, 0), (1776, 12, 14, 1), (1776, 12, 23, 0), (1776, 12, 23, 1), (1789, 7, 4, 0), (1789, 7, 4, 1), (1789, 7, 14, 0), (1789, 7, 14, 1), (1789, 7, 23, 0), (1789, 7, 23, 1), (1789, 12, 4, 0), (1789, 12, 4, 1), (1789, 12, 14, 0), (1789, 12, 14, 1), (1789, 12, 23, 0), (1789, 12, 23, 1)}
{(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)}
{}</pre>
=={{header|Maple}}==
=={{header|Maple}}==
<syntaxhighlight lang="maple">
<lang Maple>
cartmulti := proc ()
cartmulti := proc ()
local m, v;
local m, v;
Line 2,196: Line 3,276:
end if;
end if;
end proc;
end proc;
</syntaxhighlight>
</lang>
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">cartesianProduct[args__] := Flatten[Outer[List, args], Length[{args}] - 1]</syntaxhighlight>

=={{header|Maxima}}==
Using built-in function cartesian_product
<syntaxhighlight lang="maxima">
cartesian_product({1,2},{3,4});
/* {[1,3],[1,4],[2,3],[2,4]} */
cartesian_product({3,4},{1,2});
/* {[3,1],[3,2],[4,1],[4,2]} */
cartesian_product({1,2},{});
/* {} */
cartesian_product({},{1,2});
/* {} */
</syntaxhighlight>
Using built-in function cartesian_product_list
<syntaxhighlight lang="maxima">
cartesian_product_list([1,2],[3,4]);
/* [[1,3],[1,4],[2,3],[2,4]] */
cartesian_product_list([3,4],[1,2]);
/* [[3,1],[3,2],[4,1],[4,2]] */
cartesian_product_list([1,2],[]);
/* [] */
cartesian_product_list([],[1,2]);
/* [] */
</syntaxhighlight>
Using built-in function create_list
<syntaxhighlight lang="maxima">
create_list([i,j],i,[1,2],j,[3,4]);
/* [[1,3],[1,4],[2,3],[2,4]] */
create_list([i,j],i,[3,4],j,[1,2]);
/* [[3,1],[3,2],[4,1],[4,2]] */
create_list([i,j],i,[1,2],j,[]);
/* [] */
create_list([i,j],i,[],j,[1,2]);
/* [] */
</syntaxhighlight>
Extra credit
<syntaxhighlight lang="maxima">
my_cartesian(lst1,lst2):=create_list([i,j],i,lst1,j,lst2);
n_ary_cartesian(singleargument):=block(lreduce(my_cartesian,singleargument),map(flatten,%%));

[[1776,1789],[7,12],[4,14,23],[0,1]]$
n_ary_cartesian(%);
/* [[1776,7,4,0],[1776,7,4,1],[1776,7,14,0],[1776,7,14,1],[1776,7,23,0],[1776,7,23,1],[1776,12,4,0],[1776,12,4,1],[1776,12,14,0],[1776,12,14,1],[1776,12,23,0],[1776,12,23,1],[1789,7,4,0],[1789,7,4,1],[1789,7,14,0],[1789,7,14,1],[1789,7,23,0],[1789,7,23,1],[1789,12,4,0],[1789,12,4,1],[1789,12,14,0],[1789,12,14,1],[1789,12,23,0],[1789,12,23,1]] */

[[1,2,3],[30],[500,100]]$
n_ary_cartesian(%);
/* [[1,30,500],[1,30,100],[2,30,500],[2,30,100],[3,30,500],[3,30,100]] */


[[1,2,3],[],[500,100]]$
=={{header|Mathematica}}==
n_ary_cartesian(%);
<lang Mathematica>cartesianProduct[args__] := Flatten[Outer[List, args], Length[{args}] - 1]</lang>
/* [] */
</syntaxhighlight>


=={{header|Modula-2}}==
=={{header|Modula-2}}==
<lang modula2>MODULE CartesianProduct;
<syntaxhighlight lang="modula2">MODULE CartesianProduct;
FROM FormatString IMPORT FormatString;
FROM FormatString IMPORT FormatString;
FROM Terminal IMPORT WriteString,WriteLn,ReadChar;
FROM Terminal IMPORT WriteString,WriteLn,ReadChar;
Line 2,250: Line 3,381:


ReadChar
ReadChar
END CartesianProduct.</lang>
END CartesianProduct.</syntaxhighlight>

=={{header|Nim}}==
=={{header|Nim}}==
===Task: product of two lists===
===Task: product of two lists===
Line 2,260: Line 3,390:
In order to display the result using mathematical formalism, we have created a special procedure “$$” for the sequences and have overloaded the procedure “$” for tuples.
In order to display the result using mathematical formalism, we have created a special procedure “$$” for the sequences and have overloaded the procedure “$” for tuples.


<lang Nim>iterator product[T1, T2](a: openArray[T1]; b: openArray[T2]): tuple[a: T1, b: T2] =
<syntaxhighlight lang="nim">iterator product[T1, T2](a: openArray[T1]; b: openArray[T2]): tuple[a: T1, b: T2] =
# Yield the element of the cartesian product of "a" and "b".
# Yield the element of the cartesian product of "a" and "b".
# Yield tuples rather than arrays as it allows T1 and T2 to be different.
# Yield tuples rather than arrays as it allows T1 and T2 to be different.
Line 2,299: Line 3,429:
( Empty, @[1, 2])]:
( Empty, @[1, 2])]:


echo &"{$$a} x {$$b} = {$$toSeq(product(a, b))}"</lang>
echo &"{$$a} x {$$b} = {$$toSeq(product(a, b))}"</syntaxhighlight>


{{out}}
{{out}}
Line 2,314: Line 3,444:
Note that there exists in the standard module “algorithm” a procedure which computes the product of sequences of a same type. It is not recursive and, so, likely more efficient that the following version.
Note that there exists in the standard module “algorithm” a procedure which computes the product of sequences of a same type. It is not recursive and, so, likely more efficient that the following version.


<lang Nim>proc product[T](a: varargs[seq[T]]): seq[seq[T]] =
<syntaxhighlight lang="nim">proc product[T](a: varargs[seq[T]]): seq[seq[T]] =
## Return the product of several sets (sequences).
## Return the product of several sets (sequences).


Line 2,335: Line 3,465:
b = @[3, 4]
b = @[3, 4]
c = @[5, 6]
c = @[5, 6]
echo &"{a} x {b} x {c} = {product(a, b, c)}"</lang>
echo &"{a} x {b} x {c} = {product(a, b, c)}"</syntaxhighlight>


{{out}}
{{out}}
Line 2,345: Line 3,475:
With a macro, we are able to mix several value types: the “varrags” is no longer a problem as being used at compile time it may contain sequences of different types. And we are able to return tuples of n values instead of sequences of n values.
With a macro, we are able to mix several value types: the “varrags” is no longer a problem as being used at compile time it may contain sequences of different types. And we are able to return tuples of n values instead of sequences of n values.


<lang Nim>import macros
<syntaxhighlight lang="nim">import macros


macro product(args: varargs[typed]): untyped =
macro product(args: varargs[typed]): untyped =
Line 2,418: Line 3,548:
var b = @['a', 'b']
var b = @['a', 'b']
var c = @[false, true]
var c = @[false, true]
echo &"{$$a} x {$$b} x {$$c} = {$$product(a, b, c)}"</lang>
echo &"{$$a} x {$$b} x {$$c} = {$$product(a, b, c)}"</syntaxhighlight>


{{out}}
{{out}}
<pre>{1, 2} x {a, b} x {false, true} = {(1, a, false], (1, a, true], (1, b, false], (1, b, true], (2, a, false], (2, a, true], (2, b, false], (2, b, true]}</pre>
<pre>{1, 2} x {a, b} x {false, true} = {(1, a, false], (1, a, true], (1, b, false], (1, b, true], (2, a, false], (2, a, true], (2, b, false], (2, b, true]}</pre>

=={{header|OCaml}}==
=={{header|OCaml}}==
''The double semicolons are necessary only for the toplevel''
''The double semicolons are necessary only for the toplevel''


Naive but more readable version<lang ocaml>let rec product l1 l2 =
Naive but more readable version<syntaxhighlight lang="ocaml">let rec product l1 l2 =
match l1, l2 with
match l1, l2 with
| [], _ | _, [] -> []
| [], _ | _, [] -> []
Line 2,439: Line 3,568:
(*- : (int * 'a) list = []*)
(*- : (int * 'a) list = []*)
product [] [1;2];;
product [] [1;2];;
(*- : ('a * int) list = []*)</lang>
(*- : ('a * int) list = []*)</syntaxhighlight>


Implementation with a bit more tail-call optimization, introducing a helper function. The order of the result is changed but it should not be an issue for most uses.
Implementation with a bit more tail-call optimization, introducing a helper function. The order of the result is changed but it should not be an issue for most uses.
<lang ocaml>let product' l1 l2 =
<syntaxhighlight lang="ocaml">let product' l1 l2 =
let rec aux ~acc l1' l2' =
let rec aux ~acc l1' l2' =
match l1', l2' with
match l1', l2' with
Line 2,460: Line 3,589:
(*- : (int * 'a) list = []*)
(*- : (int * 'a) list = []*)
product' [] [1;2];;
product' [] [1;2];;
(*- : ('a * int) list = []*)</lang>
(*- : ('a * int) list = []*)</syntaxhighlight>
Implemented using nested folds:
Implemented using nested folds:
<lang ocaml>let cart_prod l1 l2 =
<syntaxhighlight lang="ocaml">let cart_prod l1 l2 =
List.fold_left (fun acc1 ele1 ->
List.fold_left (fun acc1 ele1 ->
List.fold_left (fun acc2 ele2 -> (ele1,ele2)::acc2) acc1 l2) [] l1 ;;
List.fold_left (fun acc2 ele2 -> (ele1,ele2)::acc2) acc1 l2) [] l1 ;;
Line 2,469: Line 3,598:
(*- : (int * char) list = [(3, 'c'); (3, 'b'); (3, 'a'); (2, 'c'); (2, 'b'); (2, 'a'); (1, 'c'); (1, 'b'); (1, 'a')]*)
(*- : (int * char) list = [(3, 'c'); (3, 'b'); (3, 'a'); (2, 'c'); (2, 'b'); (2, 'a'); (1, 'c'); (1, 'b'); (1, 'a')]*)
cart_prod [1; 2; 3] [] ;;
cart_prod [1; 2; 3] [] ;;
(*- : ('a * int) list = [] *)</lang>
(*- : ('a * int) list = [] *)</syntaxhighlight>


Extra credit function. Since in OCaml a function can return only one type, and because tuples of different arities are different types, this returns a list of lists rather than a list of tuples. Since lists are homogeneous this version is restricted to products over a ''single'' type, eg integers.
Extra credit function. Since in OCaml a function can return only one type, and because tuples of different arities are different types, this returns a list of lists rather than a list of tuples. Since lists are homogeneous this version is restricted to products over a ''single'' type, eg integers.
<lang ocaml>let rec product'' l =
<syntaxhighlight lang="ocaml">let rec product'' l =
(* We need to do the cross product of our current list and all the others
(* We need to do the cross product of our current list and all the others
* so we define a helper function for that *)
* so we define a helper function for that *)
Line 2,517: Line 3,646:
*)
*)
product'' [[1; 2; 3];[];[500; 100]];;
product'' [[1; 2; 3];[];[500; 100]];;
(*- : int list list = []*)</lang>
(*- : int list list = []*)</syntaxhighlight>


=== Better type ===
=== Better type ===


In the latter example, our function has this signature:
In the latter example, our function has this signature:
<lang ocaml>val product'' : 'a list list -> 'a list list = <fun></lang>
<syntaxhighlight lang="ocaml">val product'' : 'a list list -> 'a list list = <fun></syntaxhighlight>
This lacks clarity as those two lists are not equivalent since one replaces a tuple. We can get a better signature by creating a tuple type:
This lacks clarity as those two lists are not equivalent since one replaces a tuple. We can get a better signature by creating a tuple type:
<lang ocaml>type 'a tuple = 'a list
<syntaxhighlight lang="ocaml">type 'a tuple = 'a list


let rec product'' (l:'a list tuple) =
let rec product'' (l:'a list tuple) =
Line 2,545: Line 3,674:


type 'a tuple = 'a list
type 'a tuple = 'a list
val product'' : 'a list tuple -> 'a tuple list = <fun></lang>
val product'' : 'a list tuple -> 'a tuple list = <fun></syntaxhighlight>

=={{header|Perl}}==
=={{header|Perl}}==
==== Iterative ====
==== Iterative ====
Nested loops, with a short-circuit to quit early if any term is an empty set.
Nested loops, with a short-circuit to quit early if any term is an empty set.
<lang perl>sub cartesian {
<syntaxhighlight lang="perl">sub cartesian {
my $sets = shift @_;
my $sets = shift @_;
for (@$sets) { return [] unless @$_ }
for (@$sets) { return [] unless @$_ }
Line 2,581: Line 3,709:
product([[1,2,3], [30], [500,100] ], '%1d %1d %3d' ).
product([[1,2,3], [30], [500,100] ], '%1d %1d %3d' ).
product([[1,2,3], [], [500,100] ], '%1d %1d %3d' ).
product([[1,2,3], [], [500,100] ], '%1d %1d %3d' ).
product([[1776,1789], [7,12], [4,14,23], [0,1]], '%4d %2d %2d %1d')</lang>
product([[1776,1789], [7,12], [4,14,23], [0,1]], '%4d %2d %2d %1d')</syntaxhighlight>
{{out}}
{{out}}
<pre>(1 3) (1 4) (2 3) (2 4)
<pre>(1 3) (1 4) (2 3) (2 4)
Line 2,593: Line 3,721:
==== Glob ====
==== Glob ====
This being Perl, there's more than one way to do it. A quick demonstration of how <code>glob</code>, more typically used for filename wildcard expansion, can solve the task.
This being Perl, there's more than one way to do it. A quick demonstration of how <code>glob</code>, more typically used for filename wildcard expansion, can solve the task.
<lang perl>$tuples = [ map { [split /:/] } glob '{1,2,3}:{30}:{500,100}' ];
<syntaxhighlight lang="perl">$tuples = [ map { [split /:/] } glob '{1,2,3}:{30}:{500,100}' ];


for $a (@$tuples) { printf "(%1d %2d %3d) ", @$a; }</lang>
for $a (@$tuples) { printf "(%1d %2d %3d) ", @$a; }</syntaxhighlight>
{{out}}
{{out}}
<pre>(1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100)</pre>
<pre>(1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100)</pre>
Line 2,601: Line 3,729:
==== Modules ====
==== Modules ====
A variety of modules can do this correctly for an arbitrary number of lists (each of independent length). Arguably using modules is very idiomatic Perl.
A variety of modules can do this correctly for an arbitrary number of lists (each of independent length). Arguably using modules is very idiomatic Perl.
<lang perl>use ntheory qw/forsetproduct/;
<syntaxhighlight lang="perl">use ntheory qw/forsetproduct/;
forsetproduct { say "@_" } [1,2,3],[qw/a b c/],[qw/@ $ !/];
forsetproduct { say "@_" } [1,2,3],[qw/a b c/],[qw/@ $ !/];


Line 2,611: Line 3,739:


use Algorithm::Loops qw/NestedLoops/;
use Algorithm::Loops qw/NestedLoops/;
NestedLoops([[1,2,3],[qw/a b c/],[qw/@ $ !/]], sub { say "@_"; });</lang>
NestedLoops([[1,2,3],[qw/a b c/],[qw/@ $ !/]], sub { say "@_"; });</syntaxhighlight>

=={{header|Phix}}==
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>function cart(sequence s)
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
sequence res = {}
<span style="color: #008080;">function</span> <span style="color: #000000;">cart</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
for n=2 to length(s) do
<span style="color: #004080;">sequence</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
for i=1 to length(s[1]) do
<span style="color: #008080;">for</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
for j=1 to length(s[2]) do
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">do</span>
res = append(res,s[1][i]&s[2][j])
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">do</span>
end for
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]&</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">][</span><span style="color: #000000;">j</span><span style="color: #0000FF;">])</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
if length(s)=2 then exit end if
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
s[1..2] = {res}
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">2</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
res = {}
<span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">}</span>
end for
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
return res
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
?cart({{1,2},{3,4}})
?cart({{3,4},{1,2}})
<span style="color: #0000FF;">?</span><span style="color: #000000;">cart</span><span style="color: #0000FF;">({{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">}})</span>
?cart({{1,2},{}})
<span style="color: #0000FF;">?</span><span style="color: #000000;">cart</span><span style="color: #0000FF;">({{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">}})</span>
?cart({{},{1,2}})
<span style="color: #0000FF;">?</span><span style="color: #000000;">cart</span><span style="color: #0000FF;">({{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},{}})</span>
?cart({{1776, 1789},{7, 12},{4, 14, 23},{0, 1}})
<span style="color: #0000FF;">?</span><span style="color: #000000;">cart</span><span style="color: #0000FF;">({{},{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">}})</span>
?cart({{1, 2, 3},{30},{500, 100}})
<span style="color: #0000FF;">?</span><span style="color: #000000;">cart</span><span style="color: #0000FF;">({{</span><span style="color: #000000;">1776</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1789</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">12</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">14</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">23</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">}})</span>
?cart({{1, 2, 3},{},{500, 100}})</lang>
<span style="color: #0000FF;">?</span><span style="color: #000000;">cart</span><span style="color: #0000FF;">({{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">30</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">500</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">100</span><span style="color: #0000FF;">}})</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">cart</span><span style="color: #0000FF;">({{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">},{},{</span><span style="color: #000000;">500</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">100</span><span style="color: #0000FF;">}})</span>
<!--</syntaxhighlight>-->
{{out}}
{{out}}
<pre>
<pre>
Line 2,649: Line 3,779:
{}
{}
</pre>
</pre>

=={{header|Phixmonti}}==
=={{header|Phixmonti}}==
<lang Phixmonti>include ..\Utilitys.pmt
<syntaxhighlight lang="phixmonti">include ..\Utilitys.pmt


def cart
def cart
Line 2,681: Line 3,810:


( ( 1 2 ) ( ) ) cart
( ( 1 2 ) ( ) ) cart
drop res print nl nl</lang>
drop res print nl nl</syntaxhighlight>

=={{header|PicoLisp}}==
=={{header|PicoLisp}}==
<lang PicoLisp>(de 2lists (L1 L2)
<syntaxhighlight lang="picolisp">(de 2lists (L1 L2)
(mapcan
(mapcan
'((I)
'((I)
Line 2,709: Line 3,837:
(cartesian (1 2 3) (30) (500 100)) )
(cartesian (1 2 3) (30) (500 100)) )
(println
(println
(cartesian (1 2 3) NIL (500 100)) )</lang>
(cartesian (1 2 3) NIL (500 100)) )</syntaxhighlight>


{{out}}
{{out}}
Line 2,719: Line 3,847:
((1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100))
((1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100))
NIL</pre>
NIL</pre>

=={{header|Prolog}}==
=={{header|Prolog}}==
<syntaxhighlight lang="prolog">
<lang Prolog>
product([A|_], Bs, [A, B]) :- member(B, Bs).
product([A|_], Bs, [A, B]) :- member(B, Bs).
product([_|As], Bs, X) :- product(As, Bs, X).
product([_|As], Bs, X) :- product(As, Bs, X).
</syntaxhighlight>
</lang>
{{Out}}
{{Out}}
<pre>
<pre>
Line 2,741: Line 3,868:
=={{header|Python}}==
=={{header|Python}}==
===Using itertools===
===Using itertools===
<lang python>import itertools
<syntaxhighlight lang="python">import itertools


def cp(lsts):
def cp(lsts):
Line 2,755: Line 3,882:
print(lists, '=>')
print(lists, '=>')
pp(cp(lists), indent=2)
pp(cp(lists), indent=2)
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>[[1, 2], [3, 4]] =>
<pre>[[1, 2], [3, 4]] =>
Line 2,806: Line 3,933:
If we write ourselves a re-usable Python '''ap''' function for the case of lists (applicative functions for other 'data containers' can also be written – this one applies a list of functions to a list of values):
If we write ourselves a re-usable Python '''ap''' function for the case of lists (applicative functions for other 'data containers' can also be written – this one applies a list of functions to a list of values):


<lang python># ap (<*>) :: [(a -> b)] -> [a] -> [b]
<syntaxhighlight lang="python"># ap (<*>) :: [(a -> b)] -> [a] -> [b]
def ap(fs):
def ap(fs):
return lambda xs: foldl(
return lambda xs: foldl(
lambda a: lambda f: a + foldl(
lambda a: lambda f: a + foldl(
lambda a: lambda x: a + [f(x)])([])(xs)
lambda a: lambda x: a + [f(x)])([])(xs)
)([])(fs)</lang>
)([])(fs)</syntaxhighlight>


then one simple use of it will be to define the cartesian product of two lists (of possibly different type) as:
then one simple use of it will be to define the cartesian product of two lists (of possibly different type) as:


<lang python>ap(map(Tuple, xs))</lang>
<syntaxhighlight lang="python">ap(map(Tuple, xs))</syntaxhighlight>


where Tuple is a constructor, and xs is bound to the first of two lists. The returned value is a function which can be applied to a second list.
where Tuple is a constructor, and xs is bound to the first of two lists. The returned value is a function which can be applied to a second list.
Line 2,821: Line 3,948:
For an nAry product, we can then use a '''fold''' (catamorphism) to lift the basic function over two lists ''cartesianProduct :: [a] -> [b] -> [(a, b)]'' to a function over a list of lists:
For an nAry product, we can then use a '''fold''' (catamorphism) to lift the basic function over two lists ''cartesianProduct :: [a] -> [b] -> [(a, b)]'' to a function over a list of lists:


<lang python># nAryCartProd :: [[a], [b], [c] ...] -> [(a, b, c ...)]
<syntaxhighlight lang="python"># nAryCartProd :: [[a], [b], [c] ...] -> [(a, b, c ...)]
def nAryCartProd(xxs):
def nAryCartProd(xxs):
return foldl1(cartesianProduct)(
return foldl1(cartesianProduct)(
xxs
xxs
)</lang>
)</syntaxhighlight>


For example:
For example:


<lang python># Two lists -> list of tuples
<syntaxhighlight lang="python"># Two lists -> list of tuples




Line 2,936: Line 4,063:
# TEST ----------------------------------------------------
# TEST ----------------------------------------------------
if __name__ == '__main__':
if __name__ == '__main__':
main()</lang>
main()</syntaxhighlight>
{{Out}}
{{Out}}
<pre>Product of two lists of different types:
<pre>Product of two lists of different types:
Line 2,972: Line 4,099:
[(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)]
[(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)]
[]</pre>
[]</pre>
=={{header|Quackery}}==


<syntaxhighlight lang="quackery"> [ [] unrot
swap witheach
[ over witheach
[ over nested
swap nested join
nested dip rot join
unrot ]
drop ] drop ] is cartprod ( [ [ --> [ )

' [ 1 2 ] ' [ 3 4 ] cartprod echo cr
' [ 3 4 ] ' [ 1 2 ] cartprod echo cr
' [ 1 2 ] ' [ ] cartprod echo cr
' [ ] ' [ 1 2 ] cartprod echo cr</syntaxhighlight>

{{out}}

<pre>[ [ 1 3 ] [ 1 4 ] [ 2 3 ] [ 2 4 ] ]
[ [ 3 1 ] [ 3 2 ] [ 4 1 ] [ 4 2 ] ]
[ ]
[ ]
</pre>
=={{header|R}}==
=={{header|R}}==


<syntaxhighlight lang="r">
<lang R>
one_w_many <- function(one, many) lapply(many, function(x) c(one,x))
one_w_many <- function(one, many) lapply(many, function(x) c(one,x))


Line 2,993: Line 4,142:
prod = Reduce( '%p%', list(...) )
prod = Reduce( '%p%', list(...) )
display_prod( prod ) }
display_prod( prod ) }
</syntaxhighlight>
</lang>


Simple tests:
Simple tests:


<syntaxhighlight lang="r">
<lang R>
> display_prod( c(1, 2) %p% c(3, 4) )
> display_prod( c(1, 2) %p% c(3, 4) )
1, 3
1, 3
Line 3,010: Line 4,159:
> display_prod( c(3, 4) %p% c() )
> display_prod( c(3, 4) %p% c() )
>
>
</syntaxhighlight>
</lang>


Tougher tests:
Tougher tests:


<syntaxhighlight lang="r">
<lang R>
go( c(1776, 1789), c(7, 12), c(4, 14, 23), c(0, 1) )
go( c(1776, 1789), c(7, 12), c(4, 14, 23), c(0, 1) )
go( c(1, 2, 3), c(30), c(500, 100) )
go( c(1, 2, 3), c(30), c(500, 100) )
go( c(1, 2, 3), c(), c(500, 100) )
go( c(1, 2, 3), c(), c(500, 100) )
</syntaxhighlight>
</lang>


{{out}}
{{out}}
Line 3,058: Line 4,207:
(1, 2, 3) * () * (500, 100)
(1, 2, 3) * () * (500, 100)
</pre>
</pre>

=={{header|Racket}}==
=={{header|Racket}}==


Racket has a built-in "cartesian-product" function:
Racket has a built-in "cartesian-product" function:


<lang>#lang racket/base
<syntaxhighlight lang="text">#lang racket/base
(require rackunit
(require rackunit
;; usually, included in "racket", but we're using racket/base so we
;; usually, included in "racket", but we're using racket/base so we
Line 3,079: Line 4,227:
(cartesian-product '(1776 1789) '(7 12) '(4 14 23) '(0 1))
(cartesian-product '(1776 1789) '(7 12) '(4 14 23) '(0 1))
(cartesian-product '(1 2 3) '(30) '(500 100))
(cartesian-product '(1 2 3) '(30) '(500 100))
(cartesian-product '(1 2 3) '() '(500 100))</lang>
(cartesian-product '(1 2 3) '() '(500 100))</syntaxhighlight>


{{out}}
{{out}}
Line 3,109: Line 4,257:
'((1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100))
'((1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100))
'()</pre>
'()</pre>

=={{header|Raku}}==
=={{header|Raku}}==
(formerly Perl 6)
(formerly Perl 6)
Line 3,115: Line 4,262:
The cross meta operator X will return the cartesian product of two lists. To apply the cross meta-operator to a variable number of lists, use the reduce cross meta operator [X].
The cross meta operator X will return the cartesian product of two lists. To apply the cross meta-operator to a variable number of lists, use the reduce cross meta operator [X].


<lang perl6># cartesian product of two lists using the X cross meta-operator
<syntaxhighlight lang="raku" line># cartesian product of two lists using the X cross meta-operator
say (1, 2) X (3, 4);
say (1, 2) X (3, 4);
say (3, 4) X (1, 2);
say (3, 4) X (1, 2);
Line 3,125: Line 4,272:
say [X] (1776, 1789), (7, 12), (4, 14, 23), (0, 1);
say [X] (1776, 1789), (7, 12), (4, 14, 23), (0, 1);
say [X] (1, 2, 3), (30), (500, 100);
say [X] (1, 2, 3), (30), (500, 100);
say [X] (1, 2, 3), (), (500, 100);</lang>
say [X] (1, 2, 3), (), (500, 100);</syntaxhighlight>
{{out}}
{{out}}
<pre>((1 3) (1 4) (2 3) (2 4))
<pre>((1 3) (1 4) (2 3) (2 4))
Line 3,134: Line 4,281:
((1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100))
((1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100))
()</pre>
()</pre>

=={{header|REXX}}==
=={{header|REXX}}==
===version 1===
===version 1===
This REXX version isn't limited by the number of lists or the number of sets within a list.
This REXX version isn't limited by the number of lists or the number of sets within a list.
<lang rexx>/*REXX program calculates the Cartesian product of two arbitrary-sized lists. */
<syntaxhighlight lang="rexx">/*REXX program calculates the Cartesian product of two arbitrary-sized lists. */
@.= /*assign the default value to @. array*/
@.= /*assign the default value to @. array*/
parse arg @.1 /*obtain the optional value of @.1 */
parse arg @.1 /*obtain the optional value of @.1 */
Line 3,164: Line 4,310:
end /*i*/
end /*i*/
say 'Cartesian product of ' space(@.n) " is ───► {"substr($, 2)'}'
say 'Cartesian product of ' space(@.n) " is ───► {"substr($, 2)'}'
end /*n*/ /*stick a fork in it, we're all done. */</lang>
end /*n*/ /*stick a fork in it, we're all done. */</syntaxhighlight>
{{out|output|text=&nbsp; when using the default lists:}}
{{out|output|text=&nbsp; when using the default lists:}}
<pre>
<pre>
Line 3,175: Line 4,321:


===version 2===
===version 2===
<lang rexx>/* REXX computes the Cartesian Product of up to 4 sets */
<syntaxhighlight lang="rexx">/* REXX computes the Cartesian Product of up to 4 sets */
Call cart '{1, 2} x {3, 4}'
Call cart '{1, 2} x {3, 4}'
Call cart '{3, 4} x {1, 2}'
Call cart '{3, 4} x {1, 2}'
Line 3,238: Line 4,384:
End
End
Say ' '
Say ' '
Return 0</lang>
Return 0</syntaxhighlight>
{{out}}
{{out}}
<pre>{1, 2} x {3, 4}
<pre>{1, 2} x {3, 4}
Line 3,294: Line 4,440:
{1, 2, 3} x {} x {500, 100}
{1, 2, 3} x {} x {500, 100}
{}</pre>
{}</pre>

=={{header|Ring}}==
=={{header|Ring}}==
<lang ring>
<syntaxhighlight lang="ring">
# Project : Cartesian product of two or more lists
# Project : Cartesian product of two or more lists


Line 3,311: Line 4,456:
next
next
see nl
see nl
</syntaxhighlight>
</lang>
Output:
Output:
<pre>
<pre>
Line 3,323: Line 4,468:
(4, 1)
(4, 1)
(4, 2)
(4, 2)
</pre>
=={{header|RPL}}==
≪ → a b
≪ { }
'''IF''' a SIZE b SIZE AND '''THEN'''
1 a SIZE '''FOR''' j
1 b SIZE '''FOR''' k
a j GET b k GET 2 →LIST 1 →LIST +
'''NEXT'''
'''NEXT'''
'''END'''
≫ ≫ '<span style="color:blue">CROIX</span>' STO
{1 2} {3 4} <span style="color:blue">CROIX</span>
{3 4} {1 2} <span style="color:blue">CROIX</span>
{1 2} {} <span style="color:blue">CROIX</span>
{} {1 2} <span style="color:blue">CROIX</span>
{{out}}
<pre>
4: {(1 3) (1 4) (2 3) (2 4)}
3: {(3 1) (3 2) (4 1) (4 2)}
2: {}
1: {}
</pre>
</pre>


=={{header|Ruby}}==
=={{header|Ruby}}==
"product" is a method of arrays. It takes one or more arrays as argument and results in the Cartesian product:
"product" is a method of arrays. It takes one or more arrays as argument and results in the Cartesian product:
<lang ruby>p [1, 2].product([3, 4])
<syntaxhighlight lang="ruby">p [1, 2].product([3, 4])
p [3, 4].product([1, 2])
p [3, 4].product([1, 2])
p [1, 2].product([])
p [1, 2].product([])
Line 3,334: Line 4,501:
p [1, 2, 3].product([30], [500, 100])
p [1, 2, 3].product([30], [500, 100])
p [1, 2, 3].product([], [500, 100])
p [1, 2, 3].product([], [500, 100])
</syntaxhighlight>
</lang>
{{out}}<pre>[[1, 3], [1, 4], [2, 3], [2, 4]]
{{out}}<pre>[[1, 3], [1, 4], [2, 3], [2, 4]]
[[3, 1], [3, 2], [4, 1], [4, 2]]
[[3, 1], [3, 2], [4, 1], [4, 2]]
Line 3,345: Line 4,512:


=={{header|Rust}}==
=={{header|Rust}}==
<lang rust>fn cartesian_product(lists: &Vec<Vec<u32>>) -> Vec<Vec<u32>> {
<syntaxhighlight lang="rust">fn cartesian_product(lists: &Vec<Vec<u32>>) -> Vec<Vec<u32>> {
let mut res = vec![];
let mut res = vec![];


Line 3,386: Line 4,553:
}
}
}
}
</syntaxhighlight>
</lang>
{{out}}<pre>[1, 2] × [3, 4]
{{out}}<pre>[1, 2] × [3, 4]
[[1, 3], [1, 4], [2, 3], [2, 4]]
[[1, 3], [1, 4], [2, 3], [2, 4]]
Line 3,408: Line 4,575:
[]
[]
</pre>
</pre>

=={{header|Scala}}==
=={{header|Scala}}==
Function returning the n-ary product of an arbitrary number of lists, each of arbitrary length:
Function returning the n-ary product of an arbitrary number of lists, each of arbitrary length:


<lang scala>def cartesianProduct[T](lst: List[T]*): List[List[T]] = {
<syntaxhighlight lang="scala">def cartesianProduct[T](lst: List[T]*): List[List[T]] = {


/**
/**
Line 3,441: Line 4,607:
}
}
}
}
}</lang>
}</syntaxhighlight>
and usage:
and usage:
<lang scala>cartesianProduct(List(1, 2), List(3, 4))
<syntaxhighlight lang="scala">cartesianProduct(List(1, 2), List(3, 4))
.map(_.mkString("(", ", ", ")")).mkString("{",", ","}")</lang>
.map(_.mkString("(", ", ", ")")).mkString("{",", ","}")</syntaxhighlight>
{{out}}
{{out}}
<pre>{(1, 3), (1, 4), (2, 3), (2, 4)}</pre>
<pre>{(1, 3), (1, 4), (2, 3), (2, 4)}</pre>


<lang scala>cartesianProduct(List(3, 4), List(1, 2))
<syntaxhighlight lang="scala">cartesianProduct(List(3, 4), List(1, 2))
.map(_.mkString("(", ", ", ")")).mkString("{",", ","}")</lang>
.map(_.mkString("(", ", ", ")")).mkString("{",", ","}")</syntaxhighlight>
{{out}}
{{out}}
<pre>{(3, 1), (3, 2), (4, 1), (4, 2)}</pre>
<pre>{(3, 1), (3, 2), (4, 1), (4, 2)}</pre>


<lang scala>cartesianProduct(List(1, 2), List.empty)
<syntaxhighlight lang="scala">cartesianProduct(List(1, 2), List.empty)
.map(_.mkString("(", ", ", ")")).mkString("{",", ","}")</lang>
.map(_.mkString("(", ", ", ")")).mkString("{",", ","}")</syntaxhighlight>
{{out}}
{{out}}
<pre>{}</pre>
<pre>{}</pre>


<lang scala>cartesianProduct(List.empty, List(1, 2))
<syntaxhighlight lang="scala">cartesianProduct(List.empty, List(1, 2))
.map(_.mkString("(", ", ", ")")).mkString("{",", ","}")</lang>
.map(_.mkString("(", ", ", ")")).mkString("{",", ","}")</syntaxhighlight>
{{out}}
{{out}}
<pre>{}</pre>
<pre>{}</pre>


<lang scala>cartesianProduct(List(1776, 1789), List(7, 12), List(4, 14, 23), List(0, 1))
<syntaxhighlight lang="scala">cartesianProduct(List(1776, 1789), List(7, 12), List(4, 14, 23), List(0, 1))
.map(_.mkString("(", ", ", ")")).mkString("{",", ","}")</lang>
.map(_.mkString("(", ", ", ")")).mkString("{",", ","}")</syntaxhighlight>
{{out}}
{{out}}
<pre>{(1776, 7, 4, 0), (1776, 7, 4, 1), (1776, 7, 14, 0), (1776, 7, 14, 1), (1776, 7, 23, 0), (1776, 7, 23, 1), (1776, 12, 4, 0), (1776, 12, 4, 1), (1776, 12, 14, 0), (1776, 12, 14, 1), (1776, 12, 23, 0), (1776, 12, 23, 1), (1789, 7, 4, 0), (1789, 7, 4, 1), (1789, 7, 14, 0), (1789, 7, 14, 1), (1789, 7, 23, 0), (1789, 7, 23, 1), (1789, 12, 4, 0), (1789, 12, 4, 1), (1789, 12, 14, 0), (1789, 12, 14, 1), (1789, 12, 23, 0), (1789, 12, 23, 1)}</pre>
<pre>{(1776, 7, 4, 0), (1776, 7, 4, 1), (1776, 7, 14, 0), (1776, 7, 14, 1), (1776, 7, 23, 0), (1776, 7, 23, 1), (1776, 12, 4, 0), (1776, 12, 4, 1), (1776, 12, 14, 0), (1776, 12, 14, 1), (1776, 12, 23, 0), (1776, 12, 23, 1), (1789, 7, 4, 0), (1789, 7, 4, 1), (1789, 7, 14, 0), (1789, 7, 14, 1), (1789, 7, 23, 0), (1789, 7, 23, 1), (1789, 12, 4, 0), (1789, 12, 4, 1), (1789, 12, 14, 0), (1789, 12, 14, 1), (1789, 12, 23, 0), (1789, 12, 23, 1)}</pre>


<lang scala>cartesianProduct(List(1, 2, 3), List(30), List(500, 100))
<syntaxhighlight lang="scala">cartesianProduct(List(1, 2, 3), List(30), List(500, 100))
.map(_.mkString("(", ", ", ")")).mkString("{",", ","}")</lang>
.map(_.mkString("(", ", ", ")")).mkString("{",", ","}")</syntaxhighlight>
{{out}}
{{out}}
<pre>{(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)}</pre>
<pre>{(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)}</pre>


<lang scala>cartesianProduct(List(1, 2, 3), List.empty, List(500, 100))
<syntaxhighlight lang="scala">cartesianProduct(List(1, 2, 3), List.empty, List(500, 100))
.map(_.mkString("[", ", ", "]")).mkString("\n")</lang>
.map(_.mkString("[", ", ", "]")).mkString("\n")</syntaxhighlight>
{{out}}
{{out}}
<pre>{}</pre>
<pre>{}</pre>

=={{header|Scheme}}==
=={{header|Scheme}}==
<lang scheme>
<syntaxhighlight lang="scheme">
(define cartesian-product (lambda (xs ys)
(define cartesian-product (lambda (xs ys)
(if (or (zero? (length xs)) (zero? (length ys)))
(if (or (zero? (length xs)) (zero? (length ys)))
'()
'()
(fold append (map (\ (x) (map (\ (y) (list x y)) ys)) xs)))))
(fold append (map (lambda (x) (map (lambda (y) (list x y)) ys)) xs)))))


(define nary-cartesian-product (\ (ls)
(define nary-cartesian-product (lambda (ls)
(if (fold (\ (a b) (or a b)) (map (compose zero? length) ls))
(if (fold (lambda (a b) (or a b)) (map (compose zero? length) ls))
'()
'()
(map flatten (fold cartesian-product ls)))))
(map flatten (fold cartesian-product ls)))))
Line 3,500: Line 4,665:
> (nary-cartesian-product '((1 2)(a b)(x y)))
> (nary-cartesian-product '((1 2)(a b)(x y)))
((1 a x) (1 a y) (1 b x) (1 b y) (2 a x) (2 a y) (2 b x) (2 b y))
((1 a x) (1 a y) (1 b x) (1 b y) (2 a x) (2 a y) (2 b x) (2 b y))
</syntaxhighlight>
</lang>

=={{header|Sidef}}==
=={{header|Sidef}}==
In Sidef, the Cartesian product of an arbitrary number of arrays is built-in as ''Array.cartesian()'':
In Sidef, the Cartesian product of an arbitrary number of arrays is built-in as ''Array.cartesian()'':
<lang ruby>cartesian([[1,2], [3,4], [5,6]]).say
<syntaxhighlight lang="ruby">cartesian([[1,2], [3,4], [5,6]]).say
cartesian([[1,2], [3,4], [5,6]], {|*arr| say arr })</lang>
cartesian([[1,2], [3,4], [5,6]], {|*arr| say arr })</syntaxhighlight>


Alternatively, a simple recursive implementation:
Alternatively, a simple recursive implementation:
<lang ruby>func cartesian_product(*arr) {
<syntaxhighlight lang="ruby">func cartesian_product(*arr) {


var c = []
var c = []
Line 3,527: Line 4,691:


return r
return r
}</lang>
}</syntaxhighlight>


Completing the task:
Completing the task:
<lang ruby>say cartesian_product([1,2], [3,4])
<syntaxhighlight lang="ruby">say cartesian_product([1,2], [3,4])
say cartesian_product([3,4], [1,2])</lang>
say cartesian_product([3,4], [1,2])</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 3,538: Line 4,702:
</pre>
</pre>
The product of an empty list with any other list is empty:
The product of an empty list with any other list is empty:
<lang ruby>say cartesian_product([1,2], [])
<syntaxhighlight lang="ruby">say cartesian_product([1,2], [])
say cartesian_product([], [1,2])</lang>
say cartesian_product([], [1,2])</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 3,546: Line 4,710:
</pre>
</pre>
Extra credit:
Extra credit:
<lang ruby>cartesian_product([1776, 1789], [7, 12], [4, 14, 23], [0, 1]).each{ .say }</lang>
<syntaxhighlight lang="ruby">cartesian_product([1776, 1789], [7, 12], [4, 14, 23], [0, 1]).each{ .say }</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 3,575: Line 4,739:
</pre>
</pre>


<lang ruby>say cartesian_product([1, 2, 3], [30], [500, 100])
<syntaxhighlight lang="ruby">say cartesian_product([1, 2, 3], [30], [500, 100])
say cartesian_product([1, 2, 3], [], [500, 100])</lang>
say cartesian_product([1, 2, 3], [], [500, 100])</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 3,582: Line 4,746:
[]
[]
</pre>
</pre>

=={{header|SQL}}==
=={{header|SQL}}==
If we create lists as tables with one column, cartesian product is easy.
If we create lists as tables with one column, cartesian product is easy.
<lang sql>-- set up list 1
<syntaxhighlight lang="sql">-- set up list 1
create table L1 (value integer);
create table L1 (value integer);
insert into L1 values (1);
insert into L1 values (1);
Line 3,594: Line 4,757:
insert into L2 values (4);
insert into L2 values (4);
-- get the product
-- get the product
select * from L1, L2;</lang>
select * from L1, L2;</syntaxhighlight>
{{out}}
{{out}}
<pre> VALUE VALUE
<pre> VALUE VALUE
Line 3,601: Line 4,764:
1 4
1 4
2 3
2 3
2 4</pre>You should be able to be more explicit should get the same result:<lang sql>select * from L1 cross join L2;</lang>
2 4</pre>You should be able to be more explicit should get the same result:<syntaxhighlight lang="sql">select * from L1 cross join L2;</syntaxhighlight>
Product with an empty list works as expected (using the tables created above):
Product with an empty list works as expected (using the tables created above):
<lang sql>delete from L2;
<syntaxhighlight lang="sql">delete from L2;
select * from L1, L2;</lang>
select * from L1, L2;</syntaxhighlight>
{{out}}
{{out}}
<pre>no rows selected</pre>
<pre>no rows selected</pre>
I don't think "extra credit" is meaningful here because cartesian product is so hard-baked into SQL, so here's just one of the extra credit examples (again using the tables created above):<lang sql>insert into L1 values (3);
I don't think "extra credit" is meaningful here because cartesian product is so hard-baked into SQL, so here's just one of the extra credit examples (again using the tables created above):<syntaxhighlight lang="sql">insert into L1 values (3);
insert into L2 values (30);
insert into L2 values (30);
create table L3 (value integer);
create table L3 (value integer);
Line 3,613: Line 4,776:
insert into L3 values (100);
insert into L3 values (100);
-- product works the same for as many "lists" as you'd like
-- product works the same for as many "lists" as you'd like
select * from L1, L2, L3;</lang>
select * from L1, L2, L3;</syntaxhighlight>
{{out}}
{{out}}
<pre> VALUE VALUE VALUE
<pre> VALUE VALUE VALUE
Line 3,623: Line 4,786:
2 30 100
2 30 100
3 30 100</pre>
3 30 100</pre>

=={{header|Standard ML}}==
=={{header|Standard ML}}==
<lang sml>fun prodList (nil, _) = nil
<syntaxhighlight lang="sml">fun prodList (nil, _) = nil
| prodList ((x::xs), ys) = map (fn y => (x,y)) ys @ prodList (xs, ys)
| prodList ((x::xs), ys) = map (fn y => (x,y)) ys @ prodList (xs, ys)


fun naryProdList zs = foldl (fn (xs, ys) => map op:: (prodList (xs, ys))) [[]] (rev zs)</lang>
fun naryProdList zs = foldl (fn (xs, ys) => map op:: (prodList (xs, ys))) [[]] (rev zs)</syntaxhighlight>


{{out}}
{{out}}
Line 3,652: Line 4,814:
- naryProdList [[1, 2, 3], [], [500, 100]];
- naryProdList [[1, 2, 3], [], [500, 100]];
val it = [] : int list list</pre>
val it = [] : int list list</pre>

=={{header|Stata}}==
=={{header|Stata}}==


In Stata, the command '''[https://www.stata.com/help.cgi?fillin fillin]''' may be used to expand a dataset with all combinations of a number of variables. Thus it's easy to compute a cartesian product.
In Stata, the command '''[https://www.stata.com/help.cgi?fillin fillin]''' may be used to expand a dataset with all combinations of a number of variables. Thus it's easy to compute a cartesian product.


<lang stata>. list
<syntaxhighlight lang="stata">. list


+-------+
+-------+
Line 3,676: Line 4,837:
3. | 2 3 1 |
3. | 2 3 1 |
4. | 2 4 0 |
4. | 2 4 0 |
+-----------------+</lang>
+-----------------+</syntaxhighlight>


The other way around:
The other way around:


<lang stata>. list
<syntaxhighlight lang="stata">. list


+-------+
+-------+
Line 3,699: Line 4,860:
3. | 4 1 1 |
3. | 4 1 1 |
4. | 4 2 0 |
4. | 4 2 0 |
+-----------------+</lang>
+-----------------+</syntaxhighlight>


Note, however, that this is not equivalent to a cartesian product when one of the variables is "empty" (that is, only contains missing values).
Note, however, that this is not equivalent to a cartesian product when one of the variables is "empty" (that is, only contains missing values).


<lang stata>. list
<syntaxhighlight lang="stata">. list


+-------+
+-------+
Line 3,720: Line 4,881:
1. | 1 . 0 |
1. | 1 . 0 |
2. | 2 . 0 |
2. | 2 . 0 |
+-----------------+</lang>
+-----------------+</syntaxhighlight>


This command works also if the varaibles have different numbers of nonmissing elements. However, this requires additional code to remove the observations with missing values.
This command works also if the varaibles have different numbers of nonmissing elements. However, this requires additional code to remove the observations with missing values.


<lang stata>. list
<syntaxhighlight lang="stata">. list


+-----------+
+-----------+
Line 3,779: Line 4,940:
|---------------------|
|---------------------|
6. | 3 5 6 1 |
6. | 3 5 6 1 |
+---------------------+</lang>
+---------------------+</syntaxhighlight>

=={{header|Swift}}==
=={{header|Swift}}==


{{trans|Scala}}
{{trans|Scala}}


<lang swift>func + <T>(el: T, arr: [T]) -> [T] {
<syntaxhighlight lang="swift">func + <T>(el: T, arr: [T]) -> [T] {
var ret = arr
var ret = arr


Line 3,827: Line 4,987:
print(cartesianProduct([1776, 1789], [7, 12], [4, 14, 23], [0, 1]))
print(cartesianProduct([1776, 1789], [7, 12], [4, 14, 23], [0, 1]))
print(cartesianProduct([1, 2, 3], [30], [500, 100]))
print(cartesianProduct([1, 2, 3], [30], [500, 100]))
print(cartesianProduct([1, 2, 3], [], [500, 100])</lang>
print(cartesianProduct([1, 2, 3], [], [500, 100])</syntaxhighlight>


{{out}}
{{out}}
Line 3,837: Line 4,997:
[[1, 30, 500], [1, 30, 100], [2, 30, 500], [2, 30, 100], [3, 30, 500], [3, 30, 100]]
[[1, 30, 500], [1, 30, 100], [2, 30, 500], [2, 30, 100], [3, 30, 500], [3, 30, 100]]
[]</pre>
[]</pre>

=={{header|Tailspin}}==
=={{header|Tailspin}}==
<lang tailspin>
<syntaxhighlight lang="tailspin">
'{1,2}x{3,4} = $:[by [1,2]..., by [3,4]...];
templates cartesianProduct
' -> !OUT::write
{ product: [$(1)... -> [$]], rest: $(2..last) } -> #
when <{ rest: <[](0)> }> do $.product !
otherwise def m: $.rest(1);
{ product: [$.product... -> \(def n: $; $m... -> [$n..., $] !\)], rest: $.rest(2..last) } -> #
end cartesianProduct


'{1,2}x{3,4} = $:[[1,2],[3,4]] -> cartesianProduct;
'{3,4}x{1,2} = $:[by [3,4]..., by [1,2]...];
' -> !OUT::write
' -> !OUT::write


'{3,4}x{1,2} = $:[[3,4],[1,2]] -> cartesianProduct;
'{1,2}x{} = $:[by [1,2]..., by []...];
' -> !OUT::write
' -> !OUT::write


'{1,2}x{} = $:[[1,2],[]] -> cartesianProduct;
'{}x{1,2} = $:[by []..., by [1,2]...];
' -> !OUT::write
' -> !OUT::write


'{1776, 1789} × {7, 12} × {4, 14, 23} × {0, 1} = $:[by [1776, 1789]..., by [7, 12]..., by [4, 14, 23]..., by [0, 1]...];
'{}x{1,2} = $:[[],[1,2]] -> cartesianProduct;
' -> !OUT::write
' -> !OUT::write


'{1776, 1789} × {7, 12} × {4, 14, 23} × {0, 1} = $:[[1776, 1789], [7, 12], [4, 14, 23], [0, 1]] -> cartesianProduct;
'{1, 2, 3} × {30} × {500, 100} = $:[by [1, 2, 3] ..., by [30]..., by [500, 100]...];
' -> !OUT::write
' -> !OUT::write


'{1, 2, 3} × {30} × {500, 100} = $:[[1, 2, 3], [30], [500, 100]] -> cartesianProduct;
'{1, 2, 3} × {} × {500, 100} = $:[by [1, 2, 3]..., by []..., by [500, 100]...];
' -> !OUT::write
' -> !OUT::write


// You can also generate structures with named fields
'{1, 2, 3} × {} × {500, 100} = $:[[1, 2, 3], [], [500, 100]] -> cartesianProduct;
'year {1776, 1789} × month {7, 12} × day {4, 14, 23} = $:{by [1776, 1789]... -> (year:$), by [7, 12]... -> (month:$), by [4, 14, 23]... -> (day:$)};
' -> !OUT::write
' -> !OUT::write
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
{1,2}x{3,4} = [[1, 3], [1, 4], [2, 3], [2, 4]]
{1,2}x{3,4} = [1, 3][2, 3][1, 4][2, 4]
{3,4}x{1,2} = [[3, 1], [3, 2], [4, 1], [4, 2]]
{3,4}x{1,2} = [3, 1][4, 1][3, 2][4, 2]
{1,2}x{} = []
{1,2}x{} =
{}x{1,2} = []
{}x{1,2} =
{1776, 1789} × {7, 12} × {4, 14, 23} × {0, 1} = [[1776, 7, 4, 0], [1776, 7, 4, 1], [1776, 7, 14, 0], [1776, 7, 14, 1], [1776, 7, 23, 0], [1776, 7, 23, 1], [1776, 12, 4, 0], [1776, 12, 4, 1], [1776, 12, 14, 0], [1776, 12, 14, 1], [1776, 12, 23, 0], [1776, 12, 23, 1], [1789, 7, 4, 0], [1789, 7, 4, 1], [1789, 7, 14, 0], [1789, 7, 14, 1], [1789, 7, 23, 0], [1789, 7, 23, 1], [1789, 12, 4, 0], [1789, 12, 4, 1], [1789, 12, 14, 0], [1789, 12, 14, 1], [1789, 12, 23, 0], [1789, 12, 23, 1]]
{1776, 1789} × {7, 12} × {4, 14, 23} × {0, 1} = [1776, 7, 4, 0][1789, 7, 4, 0][1776, 12, 4, 0][1789, 12, 4, 0][1776, 7, 14, 0][1789, 7, 14, 0][1776, 12, 14, 0][1789, 12, 14, 0][1776, 7, 23, 0][1789, 7, 23, 0][1776, 12, 23, 0][1789, 12, 23, 0][1776, 7, 4, 1][1789, 7, 4, 1][1776, 12, 4, 1][1789, 12, 4, 1][1776, 7, 14, 1][1789, 7, 14, 1][1776, 12, 14, 1][1789, 12, 14, 1][1776, 7, 23, 1][1789, 7, 23, 1][1776, 12, 23, 1][1789, 12, 23, 1]
{1, 2, 3} × {30} × {500, 100} = [[1, 30, 500], [1, 30, 100], [2, 30, 500], [2, 30, 100], [3, 30, 500], [3, 30, 100]]
{1, 2, 3} × {30} × {500, 100} = [1, 30, 500][2, 30, 500][3, 30, 500][1, 30, 100][2, 30, 100][3, 30, 100]
{1, 2, 3} × {} × {500, 100} = []
{1, 2, 3} × {} × {500, 100} =
year {1776, 1789} × month {7, 12} × day {4, 14, 23} = {day=4, month=7, year=1776}{day=4, month=7, year=1789}{day=4, month=12, year=1776}{day=4, month=12, year=1789}{day=14, month=7, year=1776}{day=14, month=7, year=1789}{day=14, month=12, year=1776}{day=14, month=12, year=1789}{day=23, month=7, year=1776}{day=23, month=7, year=1789}{day=23, month=12, year=1776}{day=23, month=12, year=1789}
</pre>
</pre>

=={{header|Tcl}}==
=={{header|Tcl}}==
<lang tcl>
<syntaxhighlight lang="tcl">
proc cartesianProduct {l1 l2} {
proc cartesianProduct {l1 l2} {
set result {}
set result {}
Line 3,916: Line 5,072:
puts "result: [cartesianNaryProduct {{1 2 3} {} {500 100}}]"
puts "result: [cartesianNaryProduct {{1 2 3} {} {500 100}}]"


</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 3,929: Line 5,085:
result:
result:
</pre>
</pre>
=={{header|UNIX Shell}}==
The UNIX shells don't allow passing or returning arrays from functions (other than pass-by-name shenanigans), but as pointed out in the Perl entry, wildcard brace expansion (in bash, ksh, zsh) does a Cartesian product if there's more than one set of alternatives. It doesn't handle the empty-list case (an empty brace expansion item is treated as a single item that is equal to the empty string), but otherwise it works:


$ printf '%s' "("{1,2},{3,4}")"; printf '\n'
(1,3)(1,4)(2,3)(2,4)
$ printf '%s' "("{3,4},{1,2}")"; printf '\n'
(3,1)(3,2)(4,1)(4,2)

More than two lists is not a problem:
$ printf '%s\n' "("{1776,1789},{7,12},{4,14,23},{0,1}")"
(1776,7,4,0)
(1776,7,4,1)
(1776,7,14,0)
(1776,7,14,1)
(1776,7,23,0)
(1776,7,23,1)
(1776,12,4,0)
(1776,12,4,1)
(1776,12,14,0)
(1776,12,14,1)
(1776,12,23,0)
(1776,12,23,1)
(1789,7,4,0)
(1789,7,4,1)
(1789,7,14,0)
(1789,7,14,1)
(1789,7,23,0)
(1789,7,23,1)
(1789,12,4,0)
(1789,12,4,1)
(1789,12,14,0)
(1789,12,14,1)
(1789,12,23,0)
(1789,12,23,1)
$ printf '%s\n' "("{1,2,3},30,{500,100}")"
(1,30,500)
(1,30,100)
(2,30,500)
(2,30,100)
(3,30,500)
(3,30,100)
=={{header|Visual Basic .NET}}==
=={{header|Visual Basic .NET}}==
{{trans|C#}}
{{trans|C#}}
<lang vbnet>Imports System.Runtime.CompilerServices
<syntaxhighlight lang="vbnet">Imports System.Runtime.CompilerServices


Module Module1
Module Module1
Line 3,968: Line 5,164:
End Sub
End Sub


End Module</lang>
End Module</syntaxhighlight>
{{out}}
{{out}}
<pre>{(1, 3), (1, 4), (2, 3), (2, 4)}
<pre>{(1, 3), (1, 4), (2, 3), (2, 4)}
Line 3,977: Line 5,173:
{(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)}
{(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)}
{}</pre>
{}</pre>
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-seq}}
<syntaxhighlight lang="wren">import "./seq" for Lst

var prod2 = Fn.new { |l1, l2|
var res = []
for (e1 in l1) {
for (e2 in l2) res.add([e1, e2])
}
return res
}

var prodN = Fn.new { |ll|
if (ll.count < 2) Fiber.abort("There must be at least two lists.")
var p2 = prod2.call(ll[0], ll[1])
return ll.skip(2).reduce(p2) { |acc, l| prod2.call(acc, l) }.map { |l| Lst.flatten(l) }.toList
}

var printProdN = Fn.new { |ll|
System.print("%(ll.join(" x ")) = ")
System.write("[\n ")
System.print(prodN.call(ll).join("\n "))
System.print("]\n")
}

System.print("[1, 2] x [3, 4] = %(prodN.call([ [1, 2], [3, 4] ]))")
System.print("[3, 4] x [1, 2] = %(prodN.call([ [3, 4], [1, 2] ]))")
System.print("[1, 2] x [] = %(prodN.call([ [1, 2], [] ]))")
System.print("[] x [1, 2] = %(prodN.call([ [], [1, 2] ]))")
System.print("[1, a] x [2, b] = %(prodN.call([ [1, "a"], [2, "b"] ]))")
System.print()
printProdN.call([ [1776, 1789], [7, 12], [4, 14, 23], [0, 1] ])
printProdN.call([ [1, 2, 3], [30], [500, 100] ])
printProdN.call([ [1, 2, 3], [], [500, 100] ])
printProdN.call([ [1, 2, 3], [30], ["a", "b"] ])</syntaxhighlight>

{{out}}
<pre>
[1, 2] x [3, 4] = [[1, 3], [1, 4], [2, 3], [2, 4]]
[3, 4] x [1, 2] = [[3, 1], [3, 2], [4, 1], [4, 2]]
[1, 2] x [] = []
[] x [1, 2] = []
[1, a] x [2, b] = [[1, 2], [1, b], [a, 2], [a, b]]

[1776, 1789] x [7, 12] x [4, 14, 23] x [0, 1] =
[
[1776, 7, 4, 0]
[1776, 7, 4, 1]
[1776, 7, 14, 0]
[1776, 7, 14, 1]
[1776, 7, 23, 0]
[1776, 7, 23, 1]
[1776, 12, 4, 0]
[1776, 12, 4, 1]
[1776, 12, 14, 0]
[1776, 12, 14, 1]
[1776, 12, 23, 0]
[1776, 12, 23, 1]
[1789, 7, 4, 0]
[1789, 7, 4, 1]
[1789, 7, 14, 0]
[1789, 7, 14, 1]
[1789, 7, 23, 0]
[1789, 7, 23, 1]
[1789, 12, 4, 0]
[1789, 12, 4, 1]
[1789, 12, 14, 0]
[1789, 12, 14, 1]
[1789, 12, 23, 0]
[1789, 12, 23, 1]
]

[1, 2, 3] x [30] x [500, 100] =
[
[1, 30, 500]
[1, 30, 100]
[2, 30, 500]
[2, 30, 100]
[3, 30, 500]
[3, 30, 100]
]

[1, 2, 3] x [] x [500, 100] =
[
]

[1, 2, 3] x [30] x [a, b] =
[
[1, 30, a]
[1, 30, b]
[2, 30, a]
[2, 30, b]
[3, 30, a]
[3, 30, b]
]
</pre>


=={{header|zkl}}==
=={{header|zkl}}==
Cartesian product is build into iterators or can be done with nested
Cartesian product is build into iterators or can be done with nested
loops.
loops.
<lang zkl>zkl: Walker.cproduct(List(1,2),List(3,4)).walk().println();
<syntaxhighlight lang="zkl">zkl: Walker.cproduct(List(1,2),List(3,4)).walk().println();
L(L(1,3),L(1,4),L(2,3),L(2,4))
L(L(1,3),L(1,4),L(2,3),L(2,4))
zkl: foreach a,b in (List(1,2),List(3,4)){ print("(%d,%d) ".fmt(a,b)) }
zkl: foreach a,b in (List(1,2),List(3,4)){ print("(%d,%d) ".fmt(a,b)) }
Line 3,987: Line 5,281:


zkl: Walker.cproduct(List(3,4),List(1,2)).walk().println();
zkl: Walker.cproduct(List(3,4),List(1,2)).walk().println();
L(L(3,1),L(3,2),L(4,1),L(4,2))</lang>
L(L(3,1),L(3,2),L(4,1),L(4,2))</syntaxhighlight>


The walk method will throw an error if used on an empty iterator but the pump
The walk method will throw an error if used on an empty iterator but the pump
method doesn't.
method doesn't.
<lang zkl>zkl: Walker.cproduct(List(3,4),List).walk().println();
<syntaxhighlight lang="zkl">zkl: Walker.cproduct(List(3,4),List).walk().println();
Exception thrown: TheEnd(Ain't no more)
Exception thrown: TheEnd(Ain't no more)


Line 3,997: Line 5,291:
L()
L()
zkl: Walker.cproduct(List,List(3,4)).pump(List).println();
zkl: Walker.cproduct(List,List(3,4)).pump(List).println();
L()</lang>
L()</syntaxhighlight>
<lang zkl>zkl: Walker.cproduct(L(1776,1789),L(7,12),L(4,14,23),L(0,1)).walk().println();
<syntaxhighlight lang="zkl">zkl: Walker.cproduct(L(1776,1789),L(7,12),L(4,14,23),L(0,1)).walk().println();
L(L(1776,7,4,0),L(1776,7,4,1),L(1776,7,14,0),L(1776,7,14,1),L(1776,7,23,0),L(1776,7,23,1),L(1776,12,4,0),L(1776,12,4,1),L(1776,12,14,0),L(1776,12,14,1),L(1776,12,23,0),L(1776,12,23,1),L(1789,7,4,0),L(1789,7,4,1),L(1789,7,14,0),L(1789,7,14,1),L(1789,7,23,0),L(1789,7,23,1),L(1789,12,4,0),L(1789,12,4,1),...)
L(L(1776,7,4,0),L(1776,7,4,1),L(1776,7,14,0),L(1776,7,14,1),L(1776,7,23,0),L(1776,7,23,1),L(1776,12,4,0),L(1776,12,4,1),L(1776,12,14,0),L(1776,12,14,1),L(1776,12,23,0),L(1776,12,23,1),L(1789,7,4,0),L(1789,7,4,1),L(1789,7,14,0),L(1789,7,14,1),L(1789,7,23,0),L(1789,7,23,1),L(1789,12,4,0),L(1789,12,4,1),...)


Line 4,005: Line 5,299:


zkl: Walker.cproduct(L(1,2,3),List,L(500,100)).pump(List).println();
zkl: Walker.cproduct(L(1,2,3),List,L(500,100)).pump(List).println();
L()</lang>
L()</syntaxhighlight>

Latest revision as of 18:54, 1 May 2024

Task
Cartesian product of two or more lists
You are encouraged to solve this task according to the task description, using any language you may know.
Task

Show one or more idiomatic ways of generating the Cartesian product of two arbitrary lists in your language.

Demonstrate that your function/method correctly returns:

{1, 2} × {3, 4} = {(1, 3), (1, 4), (2, 3), (2, 4)}

and, in contrast:

{3, 4} × {1, 2} = {(3, 1), (3, 2), (4, 1), (4, 2)}

Also demonstrate, using your function/method, that the product of an empty list with any other list is empty.

{1, 2} × {} = {}
{} × {1, 2} = {}

For extra credit, show or write a function returning the n-ary product of an arbitrary number of lists, each of arbitrary length. Your function might, for example, accept a single argument which is itself a list of lists, and return the n-ary product of those lists.

Use your n-ary Cartesian product function to show the following products:

{1776, 1789} × {7, 12} × {4, 14, 23} × {0, 1}
{1, 2, 3} × {30} × {500, 100}
{1, 2, 3} × {} × {500, 100}


11l

Translation of: Go
F cart_prod(a, b)
   V p = [(0, 0)] * (a.len * b.len)
   V i = 0
   L(aa) a
      L(bb) b
         p[i++] = (aa, bb)
   R p

print(cart_prod([1, 2], [3, 4]))
print(cart_prod([3, 4], [1, 2]))
[Int] empty_array
print(cart_prod([1, 2], empty_array))
print(cart_prod(empty_array, [1, 2]))

Alternative version

F cart_prod(a, b)
   R multiloop(a, b, (aa, bb) -> (aa, bb))
Output:
[(1, 3), (1, 4), (2, 3), (2, 4)]
[(3, 1), (3, 2), (4, 1), (4, 2)]
[]
[]

Action!

DEFINE MAX_COUNT="10"
DEFINE MAX_RESULT="100"

DEFINE PTR="CARD"

PROC PrintInput(PTR ARRAY a INT count)
  INT i,j,n
  INT ARRAY tmp

  FOR i=0 TO count-1
  DO
    tmp=a(i) n=tmp(0)
    Put('[)
    FOR j=1 TO n
    DO
      PrintI(tmp(j))
      IF j<n THEN Put(',) FI
    OD
    Put('])
    IF i<count-1 THEN Put('x) FI
  OD
RETURN

PROC PrintOutput(INT ARRAY a INT groups,count)
  INT i,j,k

  Put('[)
  k=0
  FOR i=0 TO groups-1
  DO
    Put('()
    FOR j=0 TO count-1
    DO
      PrintI(a(k)) k==+1
      IF j<count-1 THEN Put(',) FI
    OD
    Put('))
    IF i<groups-1 THEN Put(',) FI
  OD
  Put('])
RETURN

PROC Product(PTR ARRAY a INT count
  INT ARRAY r INT POINTER groups)
  INT ARRAY ind(MAX_COUNT),tmp
  INT i,j,k

  IF count>MAX_COUNT THEN Break() FI
  groups^=1
  FOR i=0 TO count-1
  DO
    ind(i)=1 tmp=a(i)
    groups^==*tmp(0)
  OD
  IF groups^=0 THEN RETURN FI
  
  j=count-1 k=0
  DO
    FOR i=0 TO count-1
    DO
      tmp=a(i)
      r(k)=tmp(ind(i)) k==+1
    OD

    DO
      tmp=a(j)
      IF ind(j)<tmp(0) THEN
        ind(j)==+1
        FOR i=j+1 TO count-1
        DO
          ind(i)=1
        OD
        j=count-1
        EXIT
      ELSE
        IF j=0 THEN RETURN FI
        j==-1
      FI
    OD
  OD
RETURN

PROC Test(PTR ARRAY a INT count)
  INT ARRAY r(MAX_RESULT)
  INT groups

  IF count<2 THEN Break() FI
  Product(a,count,r,@groups)
  PrintInput(a,count)
  Put('=)
  PrintOutput(r,groups,count)
  PutE()
RETURN

PROC Main()
  INT ARRAY
    a1=[2 1 2],a2=[2 3 4],a3=[0],
    a4=[2 1776 1789],a5=[2 7 12],
    a6=[3 4 14 23],a7=[2 0 1],
    a8=[3 1 2 3],a9=[1 30],a10=[2 500 100]
  PTR ARRAY a(4)

  a(0)=a1 a(1)=a2 Test(a,2)
  a(0)=a2 a(1)=a1 Test(a,2)
  a(0)=a1 a(1)=a3 Test(a,2)
  a(0)=a3 a(1)=a1 Test(a,2) PutE()
  a(0)=a4 a(1)=a5 a(2)=a6 a(3)=a7 Test(a,4) PutE()
  a(0)=a8 a(1)=a9 a(2)=a10 Test(a,3) PutE()
  a(0)=a8 a(1)=a3 a(2)=a10 Test(a,3)
RETURN
Output:

Screenshot from Atari 8-bit computer

[1,2]x[3,4]=[(1,3),(1,4),(2,3),(2,4)]
[3,4]x[1,2]=[(3,1),(3,2),(4,1),(4,2)]
[1,2]x[]=[]
[]x[1,2]=[]
[1776,1789]x[7,12]x[4,14,23]x[0,1]=[(1776,7,4,0),(1776,7,4,1),(1776,7,14,0),(1776,7,14,1),(1776,7,23,0),(1776,7,23,1),(1776,12,4,0),1776,12,4,1),(1776,12,14,0),(1776,12,14,1),(1776,12,23,0),(1776,12,23,1),(1789,7,4,0),(1789,7,4,1),(1789,7,14,0),(1789,7,14,1),(1789,7,23,0),(1789,7,23,1),(1789,12,4,0),(1789,12,4,1),(1789,12,14,0),(1789,12,14,1),(1789,12,23,0),(1789,12,23,1)]
[1,2,3]x[30]x[500,100]=[(1,30,500),(1,30,100),(2,30,500),(2,30,100),(3,30,500),(3,30,100)]
[1,2,3]x[]x[500,100]=[]

Ada

with Ada.Text_IO;  use Ada.Text_Io;
with Ada.Containers.Doubly_Linked_Lists;
with Ada.Strings.Fixed;

procedure Cartesian is

   type Element_Type is new Long_Integer;

   package Lists is
      new Ada.Containers.Doubly_Linked_Lists (Element_Type);
   package List_Lists is
      new Ada.Containers.Doubly_Linked_Lists (Lists.List, Lists."=");

   subtype List      is Lists.List;
   subtype List_List is List_Lists.List;

   function "*" (Left, Right : List) return List_List is
      Result : List_List;
      Sub    : List;
   begin
      for Outer of Left loop
         for Inner of Right loop
            Sub.Clear;
            Sub.Append (Outer);
            Sub.Append (Inner);
            Result.Append (Sub);
         end loop;
      end loop;
      return Result;
   end "*";

   function "*" (Left  : List_List;
                 Right : List) return List_List
   is
      Result : List_List;
      Sub    : List;
   begin
      for Outer of Left loop
         for Inner of Right loop
            Sub := Outer;
            Sub.Append (Inner);
            Result.Append (Sub);
         end loop;
      end loop;
      return Result;
   end "*";

   procedure Put (L : List) is
      use Ada.Strings;
      First : Boolean := True;
   begin
      Put ("(");
      for E of L loop
         if not First then
            Put (",");
         end if;
         Put (Fixed.Trim (E'Image, Left));
         First := False;
      end loop;
      Put (")");
   end Put;

   procedure Put (LL : List_List) is
      First : Boolean := True;
   begin
      Put ("{");
      for E of LL loop
         if not First then
            Put (",");
         end if;
         Put (E);
         First := False;
      end loop;
      Put ("}");
   end Put;

   function "&" (Left : List; Right : Element_Type) return List is
      Result : List := Left;
   begin
      Result.Append (Right);
      return Result;
   end "&";

   Nil        : List renames Lists.Empty_List;
   List_1_2   : constant List := Nil & 1 & 2;
   List_3_4   : constant List := Nil & 3 & 4;
   List_Empty : constant List := Nil;
   List_1_2_3 : constant List := Nil & 1 & 2 & 3;
begin
   Put (List_1_2 * List_3_4); New_Line;

   Put (List_3_4 * List_1_2); New_Line;

   Put (List_Empty * List_1_2); New_Line;

   Put (List_1_2 * List_Empty); New_Line;

   Put (List'(Nil & 1776 & 1789) * List'(Nil & 7 & 12) *
          List'(Nil & 4 & 14 & 23) * List'(Nil & 0 & 1)); New_Line;

   Put (List_1_2_3 * List'(Nil & 30) * List'(Nil & 500 & 100)); New_Line;

   Put (List_1_2_3 * List_Empty * List'(Nil & 500 & 100)); New_Line;
end Cartesian;
Output:
{(1,3),(1,4),(2,3),(2,4)}
{(3,1),(3,2),(4,1),(4,2)}
{}
{}
{(1776,7,4,0),(1776,7,4,1),(1776,7,14,0),(1776,7,14,1),(1776,7,23,0),(1776,7,23,1),(1776,12,4,0),(1776,12,4,1),(1776,12,14,0),(1776,12,14,1),(1776,12,23,0),(1776,12,23,1),(1789,7,4,0),(1789,7,4,1),(1789,7,14,0),(1789,7,14,1),(1789,7,23,0),(1789,7,23,1),(1789,12,4,0),(1789,12,4,1),(1789,12,14,0),(1789,12,14,1),(1789,12,23,0),(1789,12,23,1)}
{(1,30,500),(1,30,100),(2,30,500),(2,30,100),(3,30,500),(3,30,100)}
{}

ALGOL 68

Using a 1-dimensional array of INT to represent a list and a 2-dimensional array ( [,]INT ) to represent a product of two (or more) lists.
A list of lists is represented by a 1-dimensional array of 1-dimensional arrays of INT ([][]INT).

BEGIN # Cartesian Product                                                    #
    # Cartesian product operators                                            #
    PRIO X = 7; # give X he same priority as *                               #
    # returns the Cartesian product of the lists a and b                     #
    OP   X = ( []INT a, b )[,]INT:
         BEGIN
            []INT a1  = a[ AT 1 ];
            []INT b1  = b[ AT 1 ];
            INT   len = UPB a1 * UPB b1;
            [ 1 : len, 1 : IF len > 0 THEN 2 ELSE 0 FI ]INT result;
            INT pos := 0;
            FOR i TO UPB a1 DO
                FOR j TO UPB b1 DO
                    pos +:= 1;
                    result[ pos, 1 ] := a1[ i ];
                    result[ pos, 2 ] := b1[ j ]
                OD
            OD;
            result
         END # X # ;
    # returns the Cartesian product of the Cartesian product a and list b    #
    OP   X = ( [,]INT a, []INT b )[,]INT:
         BEGIN
            [,]INT a1   = a[ AT 1, AT 1 ];
            []INT  b1   = b[ AT 1 ];
            INT   len   = 1 UPB a1 * UPB b1;
            INT   width = IF len <= 0 THEN 0 ELSE 2 UPB a1 + 1 FI;
            [ 1 : len, 1 : width  ]INT result;
            INT pos := 0;
            FOR i TO 1 UPB a1 DO
                FOR j TO UPB b1 DO
                    result[ pos +:= 1, 1 : width - 1 ] := a1[ i, : ];
                    result[ pos, width ]               := b1[ j ]
                OD
            OD;
            result
         END # X # ;
    # returns the Cartesian product of the lists in a                        #
    OP   X = ( [][]INT a )[,]INT:
         IF UPB a <= LWB a
         THEN # zero or 1 list                                               #
              [,]INT()
         ELSE # 2 or more lists                                              #
              FLEX[ 1 : 0, 1 : 0 ]INT result := a[ LWB a ] X a[ LWB a + 1 ];
              FOR i FROM LWB a + 2 TO UPB a DO
                  result := result X a[ i ]
              OD;
              result
         FI # X # ;
    # print a Cartesian product                                              #
    PROC print product = ( [,]INT p )VOID:
         BEGIN
            print( ( "[" ) );
            STRING close := "]";
            STRING open  := "(";
            FOR i FROM 1 LWB p TO 1 UPB p DO
                STRING separator := open;
                FOR j FROM 2 LWB p TO 2 UPB p DO
                    print( ( separator, whole( p[ i, j ], 0 ) ) );
                    separator := ","
                OD;
                open  := "),(";
                close := ")]"
            OD;
            print( ( close ) )
         END # print product # ;
    # print a list                                                           #
    PROC print list = ( []INT t )VOID:
         BEGIN
            print( ( "[" ) );
            STRING separator := "";
            FOR i FROM LWB t TO UPB t DO
                print( ( separator, whole( t[ i ], 0 ) ) );
                separator := ","
            OD;
            print( ( "]" ) )
         END # print list # ;
    BEGIN # test the X operators                                             #
        # prints the product of two lists                                    #
        PROC print lxl = ( []INT a, b )VOID:
             BEGIN
                print list( a );print( ( "X" ) );print list( b );
                print( ( "=" ) );print product( a X b );
                print( ( newline ) )
             END # print lxl # ;
        # prints the product of a list of lists                              #
        PROC print xll = ( [][]INT a )VOID:
             IF LWB a < UPB a THEN                
                # non empty list of lists                                    #
                print list( a[ LWB a ] );
                FOR i FROM LWB a + 1 TO UPB a DO
                    print( ( "X" ) );print list( a[ i ] )
                OD;
                print( ( "=" ) );print product( X a );
                print( ( newline ) )
             FI # print xll # ;
        print lxl( ( 1, 2 ), ( 3, 4 ) );
        print lxl( ( 3, 4 ), ( 1, 2 ) );
        print lxl( ( 1, 2 ), ()       );
        print lxl( (),       ( 1, 2 ) );
        print xll( ( ( 1776, 1789 ), ( 7, 12 ), ( 4, 14, 23 ), ( 0, 1 ) ) );
        print xll( ( ( 1, 2, 3 ), ( 30 ), ( 500, 100 ) ) );
        print xll( ( ( 1, 2, 3 ), (),     ( 500, 100 ) ) )
    END
END
Output:
[1,2]X[3,4]=[(1,3),(1,4),(2,3),(2,4)]
[3,4]X[1,2]=[(3,1),(3,2),(4,1),(4,2)]
[1,2]X[]=[]
[]X[1,2]=[]
[1776,1789]X[7,12]X[4,14,23]X[0,1]=[(1776,7,4,0),(1776,7,4,1),(1776,7,14,0),(1776,7,14,1),(1776,7,23,0),(1776,7,23,1),(1776,12,4,0),(1776,12,4,1),(1776,12,14,0),(1776,12,14,1),(1776,12,23,0),(1776,12,23,1),(1789,7,4,0),(1789,7,4,1),(1789,7,14,0),(1789,7,14,1),(1789,7,23,0),(1789,7,23,1),(1789,12,4,0),(1789,12,4,1),(1789,12,14,0),(1789,12,14,1),(1789,12,23,0),(1789,12,23,1)]
[1,2,3]X[30]X[500,100]=[(1,30,500),(1,30,100),(2,30,500),(2,30,100),(3,30,500),(3,30,100)]
[1,2,3]X[]X[500,100]=[]

APL

APL has a built-in outer product operator: X ∘.F Y will get you an ⍴X-by-⍴Y matrix containing every corresponding value of x F y for all x∊X, y∊Y.

The Cartesian product can therefore be expressed as ∘.,, but as that would return a matrix, and the task is asking for a list, you also need to ravel the result.

cart  ,∘.,
Output:
      1 2 cart 3 4
 1 3  1 4  2 3  2 4 
      3 4 cart 1 2
 3 1  3 2  4 1  4 2 
      1 2 cart ⍬   ⍝ empty output

      ⍬ cart 1 2   ⍝ empty output again

This can be reduced over a list of lists to generate the Cartesian product of an arbitrary list of lists.

nary_cart  (,∘.,)/
Output:

The items are listed on separate lines (using ↑) for clarity.

      ↑nary_cart (1776 1789)(7 12)(4 14 23)(0 1)
1776  7  4 0
1776  7  4 1
1776  7 14 0
1776  7 14 1
1776  7 23 0
1776  7 23 1
1776 12  4 0
1776 12  4 1
1776 12 14 0
1776 12 14 1
1776 12 23 0
1776 12 23 1
1789  7  4 0
1789  7  4 1
1789  7 14 0
1789  7 14 1
1789  7 23 0
1789  7 23 1
1789 12  4 0
1789 12  4 1
1789 12 14 0
1789 12 14 1
1789 12 23 0
1789 12 23 1
      ↑nary_cart(1 2 3)(,30)(50 100)
1 30  50
1 30 100
2 30  50
2 30 100
3 30  50
3 30 100
      ↑nary_cart(1 2 3)(⍬)(50 100)  ⍝ empty output

AppleScript

-- CARTESIAN PRODUCTS ---------------------------------------------------------

-- Two lists:

-- cartProd :: [a] -> [b] -> [(a, b)]
on cartProd(xs, ys)
    script
        on |λ|(x)
            script
                on |λ|(y)
                    [[x, y]]
                end |λ|
            end script
            concatMap(result, ys)
        end |λ|
    end script
    concatMap(result, xs)
end cartProd

-- N-ary – a function over a list of lists:

-- cartProdNary :: [[a]] -> [[a]]
on cartProdNary(xss)
    script
        on |λ|(accs, xs)
            script
                on |λ|(x)
                    script
                        on |λ|(a)
                            {x & a}
                        end |λ|
                    end script
                    concatMap(result, accs)
                end |λ|
            end script
            concatMap(result, xs)
        end |λ|
    end script
    foldr(result, {{}}, xss)
end cartProdNary

-- TESTS ----------------------------------------------------------------------
on run
    set baseExamples to unlines(map(show, ¬
        [cartProd({1, 2}, {3, 4}), ¬
            cartProd({3, 4}, {1, 2}), ¬
            cartProd({1, 2}, {}), ¬
            cartProd({}, {1, 2})]))
    
    set naryA to unlines(map(show, ¬
        cartProdNary([{1776, 1789}, {7, 12}, {4, 14, 23}, {0, 1}])))
    
    set naryB to show(cartProdNary([{1, 2, 3}, {30}, {500, 100}]))
    
    set naryC to show(cartProdNary([{1, 2, 3}, {}, {500, 100}]))
    
    intercalate(linefeed & linefeed, {baseExamples, naryA, naryB, naryC})
end run


-- GENERIC FUNCTIONS ----------------------------------------------------------

-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
    set lst to {}
    set lng to length of xs
    tell mReturn(f)
        repeat with i from 1 to lng
            set lst to (lst & |λ|(item i of xs, i, xs))
        end repeat
    end tell
    return lst
end concatMap

-- foldr :: (a -> b -> a) -> a -> [b] -> a
on foldr(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from lng to 1 by -1
            set v to |λ|(v, item i of xs, i, xs)
        end repeat
        return v
    end tell
end foldr

-- intercalate :: Text -> [Text] -> Text
on intercalate(strText, lstText)
    set {dlm, my text item delimiters} to {my text item delimiters, strText}
    set strJoined to lstText as text
    set my text item delimiters to dlm
    return strJoined
end intercalate

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map

-- Lift 2nd class handler function into 1st class script wrapper 
-- mReturn :: Handler -> Script
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

-- show :: a -> String
on show(e)
    set c to class of e
    if c = list then
        script serialized
            on |λ|(v)
                show(v)
            end |λ|
        end script
        
        "[" & intercalate(", ", map(serialized, e)) & "]"
    else if c = record then
        script showField
            on |λ|(kv)
                set {k, ev} to kv
                "\"" & k & "\":" & show(ev)
            end |λ|
        end script
        
        "{" & intercalate(", ", ¬
            map(showField, zip(allKeys(e), allValues(e)))) & "}"
    else if c = date then
        "\"" & iso8601Z(e) & "\""
    else if c = text then
        "\"" & e & "\""
    else if (c = integer or c = real) then
        e as text
    else if c = class then
        "null"
    else
        try
            e as text
        on error
            ("«" & c as text) & "»"
        end try
    end if
end show

-- unlines :: [String] -> String
on unlines(xs)
    intercalate(linefeed, xs)
end unlines
Output:
[[1, 3], [1, 4], [2, 3], [2, 4]]
[[3, 1], [3, 2], [4, 1], [4, 2]]
[]
[]

[1776, 7, 4, 0]
[1776, 7, 4, 1]
[1776, 7, 14, 0]
[1776, 7, 14, 1]
[1776, 7, 23, 0]
[1776, 7, 23, 1]
[1776, 12, 4, 0]
[1776, 12, 4, 1]
[1776, 12, 14, 0]
[1776, 12, 14, 1]
[1776, 12, 23, 0]
[1776, 12, 23, 1]
[1789, 7, 4, 0]
[1789, 7, 4, 1]
[1789, 7, 14, 0]
[1789, 7, 14, 1]
[1789, 7, 23, 0]
[1789, 7, 23, 1]
[1789, 12, 4, 0]
[1789, 12, 4, 1]
[1789, 12, 14, 0]
[1789, 12, 14, 1]
[1789, 12, 23, 0]
[1789, 12, 23, 1]

[[1, 30, 500], [1, 30, 100], [2, 30, 500], [2, 30, 100], [3, 30, 500], [3, 30, 100]]

[]

Arturo

Translation of: Ruby
loop [
    [[1 2][3 4]] 
    [[3 4][1 2]]
    [[1 2][]]
    [[][1 2]] 
    [[1776 1789][7 12][4 14 23][0 1]]
    [[1 2 3][30][500 100]] 
    [[1 2 3][][500 100]] 
] 'lst [
    print as.code product.cartesian lst
]
Output:
[[1 3] [1 4] [2 3] [2 4]]
[[3 1] [3 2] [4 1] [4 2]]
[]
[]
[[1776 7 4 0] [1776 7 4 1] [1776 7 14 0] [1776 7 14 1] [1776 7 23 0] [1776 7 23 1] [1776 12 4 0] [1776 12 4 1] [1776 12 14 0] [1776 12 14 1] [1776 12 23 0] [1776 12 23 1] [1789 7 4 0] [1789 7 4 1] [1789 7 14 0] [1789 7 14 1] [1789 7 23 0] [1789 7 23 1] [1789 12 4 0] [1789 12 4 1] [1789 12 14 0] [1789 12 14 1] [1789 12 23 0] [1789 12 23 1]]
[[1 30 500] [1 30 100] [2 30 500] [2 30 100] [3 30 500] [3 30 100]]
[]

AutoHotkey

example := [
(join,
[[1, 2], [3, 4]]
[[3, 4], [1, 2]]
[[1, 2], []]
[[], [1, 2]]
[[1776, 1789], [7, 12], [4, 14, 23], [0, 1]]
[[1, 2, 3], [30] , [500, 100]]
[[1, 2, 3], [] , [500, 100]]
)]

for i, obj in example
{
    Product := CartesianProduct(obj)
    out := dispRes(Product)
    result .= out "`n`n"
}
MsgBox % result
return

dispRes(Product){
    for i, o in Product
    {
        for j, v in o
            output .= v ", "
        
        output := Trim(output, ", ")
        output .= "], ["
    }
    return "[[" trim(output, ", []") "]]"
}

CartesianProduct(obj){
    CP(obj, Product:=[], [])
    return Product
}

CP(obj, Product, stack, v:=""){
    oClone := obj.clone()
    oClone.RemoveAt(1)
    stack.= v ","
    
    for i, o in obj
    {
        for j, v in o
            CP(oClone, Product, stack, v)
        return
    }
    stack := trim(stack, ",")
    oTemp := []
    for i, v in StrSplit(stack, ",")
        oTemp.Push(v)
    Product.push(oTemp)
}
Output:
[[1, 3], [1, 4], [2, 3], [2, 4]]
[[3, 1], [3, 2], [4, 1], [4, 2]]
[]
[]
[[1776, 7, 4, 0], [1776, 7, 4, 1], [1776, 7, 14, 0], [1776, 7, 14, 1], [1776, 7, 23, 0], [1776, 7, 23, 1], [1776, 12, 4, 0], [1776, 12, 4, 1], [1776, 12, 14, 0], [1776, 12, 14, 1], [1776, 12, 23, 0], [1776, 12, 23, 1], [1789, 7, 4, 0], [1789, 7, 4, 1], [1789, 7, 14, 0], [1789, 7, 14, 1], [1789, 7, 23, 0], [1789, 7, 23, 1], [1789, 12, 4, 0], [1789, 12, 4, 1], [1789, 12, 14, 0], [1789, 12, 14, 1], [1789, 12, 23, 0], [1789, 12, 23, 1]]
[[1, 30, 500], [1, 30, 100], [2, 30, 500], [2, 30, 100], [3, 30, 500], [3, 30, 100]]
[]

Bracmat

( ( mul
  =   R a b A B
    .   :?R
      & !arg:(.?A) (.?B)
      & (   !A
          :   ?
              ( %@?a
              &   !B
                :   ?
                    ( (%@?b|(.?b))
                    & !R (.!a !b):?R
                    & ~
                    )
                    ?
              )
              ?
        | (.!R)
        )
  )
& ( cartprod
  =   a
    .   !arg:%?a %?arg&mul$(!a cartprod$!arg)
      | !arg
  )
&   out
  $ ( cartprod
    $ ( (.1776 1789)
        (.7 12)
        (.4 14 23)
        (.0 1)
      )
    )
& out$(cartprod$((.1 2 3) (.30) (.500 100)))
& out$(cartprod$((.1 2 3) (.) (.500 100)))
)
.   (.1776 7 4 0)
    (.1776 7 4 1)
    (.1776 7 14 0)
    (.1776 7 14 1)
    (.1776 7 23 0)
    (.1776 7 23 1)
    (.1776 12 4 0)
    (.1776 12 4 1)
    (.1776 12 14 0)
    (.1776 12 14 1)
    (.1776 12 23 0)
    (.1776 12 23 1)
    (.1789 7 4 0)
    (.1789 7 4 1)
    (.1789 7 14 0)
    (.1789 7 14 1)
    (.1789 7 23 0)
    (.1789 7 23 1)
    (.1789 12 4 0)
    (.1789 12 4 1)
    (.1789 12 14 0)
    (.1789 12 14 1)
    (.1789 12 23 0)
    (.1789 12 23 1)

.   (.1 30 500)
    (.1 30 100)
    (.2 30 500)
    (.2 30 100)
    (.3 30 500)
    (.3 30 100)
.

BASIC

Applesoft BASIC

Works with: Chipmunk Basic
Works with: GW-BASIC
100 HOME : rem  10 CLS FOR Chipmunk Basic & GW-BASIC
110 DIM array(2,2)
120 array(1,1) = 1 : array(1,2) = 2
130 array(2,1) = 3 : array(2,2) = 4
140 GOSUB 190
150 array(1,1) = 3 : array(1,2) = 4
160 array(2,1) = 1 : array(2,2) = 2
170 GOSUB 190
180 END
190 rem SUB cartesian(list)
200  u1 = 2 : u2 = 2
210  FOR i = 1 TO u1
220    PRINT "{ ";
230    FOR j = 1 TO u2
240      PRINT array(i,j);
250      IF j < u1 THEN PRINT ", ";
260    NEXT j
270    PRINT "}";
280    IF i < u2 THEN PRINT " x ";
290  NEXT i
300  PRINT " = { ";
310  FOR i = 1 TO u1
320    FOR j = 1 TO u2
330      PRINT "{ "; array(1,i); ", "; array(2,j); "} ";
340      IF i < u2 THEN PRINT ", ";
350      IF i => u2 THEN IF j < u1 THEN PRINT ", ";
360    NEXT j
370  NEXT i
380  PRINT "}"
390 RETURN

BASIC256

arraybase 1
subroutine cartesian(list)
	u1 = list[?][]
	u2 = list[][?]

	for i = 1 to u1
		print "{";
		for j = 1 to u2
			print list[i,j];
			if j < u1 then print ", ";
		next
		print "}";
		if i < u2 then print " x ";
	next i
	print " = { ";
	for i = 1 to u1
		for j = 1 to u2
			print "{"; list[1, i]; ", "; list[2, j]; "} ";
			if i < u2 then
				print ", ";
			else
				if j < u1 then print ", ";
			end if
		next j
	next i
	print "}"
end subroutine

dim list1 = {{1,2},{3,4}}
dim list2 = {{3,4},{1,2}}
call cartesian(list1)
call cartesian(list2)
end
Output:
{1, 2} x {3, 4} = { {1, 3} , {1, 4} , {2, 3} , {2, 4} }
{3, 4} x {1, 2} = { {3, 1} , {3, 2} , {4, 1} , {4, 2} }

Chipmunk Basic

Works with: Chipmunk Basic version 3.6.4
100 cls
110 dim array(2,2)
120 array(1,1) = 1 : array(1,2) = 2
130 array(2,1) = 3 : array(2,2) = 4
140 gosub 190
150 array(1,1) = 3 : array(1,2) = 4
160 array(2,1) = 1 : array(2,2) = 2
170 gosub 190
180 end
190 rem sub cartesian(list)
200  u1 = 2 : u2 = 2
210  for i = 1 to u1
220    print "{ ";
230    for j = 1 to u2
240      print array(i,j);
250      if j < u1 then print ", ";
260    next j
270    print "}";
280    if i < u2 then print " x ";
290  next i
300  print " = { ";
310  for i = 1 to u1
320    for j = 1 to u2
330      print "{ ";array(1,i);", ";array(2,j);"} ";
340      if i < u2 then
350        print ", ";
360      else
370        if j < u1 then print ", ";
380      endif
390    next j
400  next i
410  print "}"
420 return

Gambas

Public array[2, 2] As Integer

Public Sub Main()
  
  array[0, 0] = 1
  array[0, 1] = 2 
  array[1, 0] = 3
  array[1, 1] = 4 
  cartesian(array) 
  array[0, 0] = 3
  array[0, 1] = 4 
  array[1, 0] = 1
  array[1, 1] = 2 
  cartesian(array)
  
End

Sub cartesian(arr As Integer[]) 
  
  Dim u1 As Integer = arr.Max - 2
  Dim u2 As Integer = arr.Max - 2
  Dim i As Integer, j As Integer
  
  For i = 0 To u1
    Print "{"; 
    For j = 0 To u2
      Print arr[i, j]; 
      If j < u1 Then Print ","; 
    Next
    Print "}"; 
    If i < u2 Then Print " x "; 
  Next 
  Print " = {"; 
  For i = 0 To u1
    For j = 0 To u2
      Print "{"; arr[0, i]; ","; arr[1, j]; "}"; 
      If i < u2 Then 
        Print ", "; 
      Else 
        If j < u1 Then Print ", "; 
      End If 
    Next
  Next
  Print "}" 
  
End Sub

GW-BASIC

Works with: Chipmunk Basic
Works with: PC-BASIC version any
Works with: QBasic
Works with: MSX-BASIC
100 CLS
110 DIM ARR(2,2)
120 ARR(1,1) = (1) : ARR(1,2) = (2)
130 ARR(2,1) = (3) : ARR(2,2) = (4)
140 GOSUB 190
150 ARR(1,1) = 3 : ARR(1,2) = 4
160 ARR(2,1) = 1 : ARR(2,2) = 2
170 GOSUB 190
180 END
190 REM SUB cartesian(list)
200  U1 = 2 : U2 = 2
210  FOR I = 1 TO U1
220    PRINT "{";
230    FOR J = 1 TO U2
240      PRINT ARR(I,J);
250      IF J < U1 THEN PRINT ",";
260    NEXT J
270    PRINT "}";
280    IF I < U2 THEN PRINT " x ";
290  NEXT I
300  PRINT " = {";
310  FOR I = 1 TO U1
320    FOR J = 1 TO U2
330      PRINT "{"; ARR(1,I); ","; ARR(2,J); "}";
340      IF I < U2 THEN PRINT ", ";
350      IF I => U2 THEN IF J < U1 THEN PRINT ",";
360    NEXT J
370  NEXT I
380  PRINT "}"
390 RETURN

MSX Basic

Works with: MSX BASIC version any

The GW-BASIC solution works without any changes.

QBasic

Works with: QBasic version 1.1
Works with: QuickBasic version 4.5
DECLARE SUB cartesian (arr!())

CLS
DIM array(2, 2)
array(1, 1) = 1: array(1, 2) = 2
array(2, 1) = 3: array(2, 2) = 4
CALL cartesian(array())
array(1, 1) = 3: array(1, 2) = 4
array(2, 1) = 1: array(2, 2) = 2
CALL cartesian(array())
END

SUB cartesian (arr())
u1 = 2: u2 = 2
FOR i = 1 TO u1
  PRINT "{";
  FOR j = 1 TO u2
    PRINT arr(i, j);
    IF j < u1 THEN PRINT ",";
  NEXT j
  PRINT "}";
  IF i < u2 THEN PRINT " x ";
NEXT i
PRINT " = {";
FOR i = 1 TO u1
  FOR j = 1 TO u2
    PRINT "{"; arr(1, i); ","; arr(2, j); "}";
    IF i < u2 THEN
      PRINT ", ";
    ELSE
      IF j < u1 THEN PRINT ", ";
    END IF
  NEXT j
NEXT i
PRINT "}"
END SUB

Run BASIC

Works with: Just BASIC
Works with: Liberty BASIC
cls
dim array(2,2)
array(1,1) = 1 : array(1,2) = 2
array(2,1) = 3 : array(2,2) = 4
gosub [cartesian]
array(1,1) = 3 : array(1,2) = 4
array(2,1) = 1 : array(2,2) = 2
gosub [cartesian]
end

[cartesian]
u1 = 2 : u2 = 2
for i = 1 to u1
  print "{";
  for j = 1 to u2
    print array(i,j);
    if j < u1 then print ",";
  next j
  print "}";
  if i < u2 then print " x ";
next i
print " = {";
for i = 1 to u1
  for j = 1 to u2
    print "{"; array(1,i); ","; array(2,j); "}";
    if i < u2 then
      print ",";
    else
      if j < u1 then print ",";
    end if
  next j
next i
print "}"
return

C

Recursive implementation for computing the Cartesian product of lists. In the pursuit of making it as interactive as possible, the parsing function ended up taking the most space. The product set expression must be supplied enclosed by double quotes. Prints out usage on incorrect invocation.

#include<string.h>
#include<stdlib.h>
#include<stdio.h>

void cartesianProduct(int** sets, int* setLengths, int* currentSet, int numSets, int times){
	int i,j;
	
	if(times==numSets){
		printf("(");
		for(i=0;i<times;i++){
			printf("%d,",currentSet[i]);
		}
		printf("\b),");
	}
	else{
		for(j=0;j<setLengths[times];j++){
			currentSet[times] = sets[times][j];
			cartesianProduct(sets,setLengths,currentSet,numSets,times+1);
		}
	}
}

void printSets(int** sets, int* setLengths, int numSets){
	int i,j;
	
	printf("\nNumber of sets : %d",numSets);
	
	for(i=0;i<numSets+1;i++){
		printf("\nSet %d : ",i+1);
		for(j=0;j<setLengths[i];j++){
			printf(" %d ",sets[i][j]);
		}
	}
}

void processInputString(char* str){
	int **sets, *currentSet, *setLengths, setLength, numSets = 0, i,j,k,l,start,counter=0;
	char *token,*holder,*holderToken;
	
	for(i=0;str[i]!=00;i++)
		if(str[i]=='x')
			numSets++;
		
	if(numSets==0){
			printf("\n%s",str);
			return;
	}
		
	currentSet = (int*)calloc(sizeof(int),numSets + 1);
	
	setLengths = (int*)calloc(sizeof(int),numSets + 1);
	
	sets = (int**)malloc((numSets + 1)*sizeof(int*));
	
	token = strtok(str,"x");
	
	while(token!=NULL){
		holder = (char*)malloc(strlen(token)*sizeof(char));
		
		j = 0;
		
		for(i=0;token[i]!=00;i++){
			if(token[i]>='0' && token[i]<='9')
				holder[j++] = token[i];
			else if(token[i]==',')
				holder[j++] = ' ';
		}
		holder[j] = 00;
		
		setLength = 0;
		
		for(i=0;holder[i]!=00;i++)
			if(holder[i]==' ')
				setLength++;
			
		if(setLength==0 && strlen(holder)==0){
			printf("\n{}");
			return;
		}
		
		setLengths[counter] = setLength+1;
		
		sets[counter] = (int*)malloc((1+setLength)*sizeof(int));
		
		k = 0;
		
		start = 0;
		
		for(l=0;holder[l]!=00;l++){
			if(holder[l+1]==' '||holder[l+1]==00){
				holderToken = (char*)malloc((l+1-start)*sizeof(char));
				strncpy(holderToken,holder + start,l+1-start);
				sets[counter][k++] = atoi(holderToken);
				start = l+2;
			}
		}
		
		counter++;
		token = strtok(NULL,"x");
	}
	
	printf("\n{");
	cartesianProduct(sets,setLengths,currentSet,numSets + 1,0);
	printf("\b}");
	
}

int main(int argC,char* argV[])
{
	if(argC!=2)
		printf("Usage : %s <Set product expression enclosed in double quotes>",argV[0]);
	else
		processInputString(argV[1]);
	
	return 0;
}

Invocation and output :

C:\My Projects\threeJS>cartesianProduct.exe "{1,2} x {3,4}"

{(1,3),(1,4),(2,3),(2,4)}
C:\My Projects\threeJS>cartesianProduct.exe "{3,4} x {1,2}"

{(3,1),(3,2),(4,1),(4,2)}
C:\My Projects\threeJS>cartesianProduct.exe "{1,2} x {}"

{}
C:\My Projects\threeJS>cartesianProduct.exe "{} x {1,2}"

{}
C:\My Projects\threeJS>cartesianProduct.exe "{1776, 1789} x {7, 12} x {4, 14, 23} x {0, 1}"

{(1776,7,4,0),(1776,7,4,1),(1776,7,14,0),(1776,7,14,1),(1776,7,23,0),(1776,7,23,1),(1776,12,4,0),(1776,12,4,1),(1776,12,14,0),(1776,12,14,1),(1776,12,23,0),(1776,12,23,1),(1789,7,4,0),(1789,9,12,14,1),(1789,12,23,0),(1789,12,23,1)}
C:\My Projects\threeJS>cartesianProduct.exe "{1, 2, 3} x {30} x {500, 100}"

{(1,30,500),(1,30,100),(2,30,500),(2,30,100),(3,30,500),(3,30,100)}
C:\My Projects\threeJS>cartesianProduct.exe "{1, 2, 3} x {} x {500, 100}"

{}

C#

using System;
public class Program
{
    public static void Main()
    {
        int[] empty = new int[0];
        int[] list1 = { 1, 2 };
        int[] list2 = { 3, 4 };
        int[] list3 = { 1776, 1789 };
        int[] list4 = { 7, 12 };
        int[] list5 = { 4, 14, 23 };
        int[] list6 = { 0, 1 };
        int[] list7 = { 1, 2, 3 };
        int[] list8 = { 30 };
        int[] list9 = { 500, 100 };
        
        foreach (var sequenceList in new [] {
            new [] { list1, list2 },
            new [] { list2, list1 },
            new [] { list1, empty },
            new [] { empty, list1 },
            new [] { list3, list4, list5, list6 },
            new [] { list7, list8, list9 },
            new [] { list7, empty, list9 }
        }) {
            var cart = sequenceList.CartesianProduct()
                .Select(tuple => $"({string.Join(", ", tuple)})");
            Console.WriteLine($"{{{string.Join(", ", cart)}}}");
        }
    }
}

public static class Extensions
{
    public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences) {
        IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
        return sequences.Aggregate(
            emptyProduct,
            (accumulator, sequence) =>
            from acc in accumulator
            from item in sequence
            select acc.Concat(new [] { item }));
    }
}
Output:
{(1, 3), (1, 4), (2, 3), (2, 4)}
{(3, 1), (3, 2), (4, 1), (4, 2)}
{}
{}
{(1776, 7, 4, 0), (1776, 7, 4, 1), (1776, 7, 14, 0), (1776, 7, 14, 1), (1776, 7, 23, 0), (1776, 7, 23, 1), (1776, 12, 4, 0), (1776, 12, 4, 1), (1776, 12, 14, 0), (1776, 12, 14, 1), (1776, 12, 23, 0), (1776, 12, 23, 1), (1789, 7, 4, 0), (1789, 7, 4, 1), (1789, 7, 14, 0), (1789, 7, 14, 1), (1789, 7, 23, 0), (1789, 7, 23, 1), (1789, 12, 4, 0), (1789, 12, 4, 1), (1789, 12, 14, 0), (1789, 12, 14, 1), (1789, 12, 23, 0), (1789, 12, 23, 1)}
{(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)}
{}

If the number of lists is known, LINQ provides an easier solution:

public static void Main()
{
    ///...
    var cart1 =
        from a in list1
        from b in list2
        select (a, b); // C# 7.0 tuple
    Console.WriteLine($"{{{string.Join(", ", cart1)}}}");
        
    var cart2 =
        from a in list7
        from b in list8
        from c in list9
        select (a, b, c);
    Console.WriteLine($"{{{string.Join(", ", cart2)}}}");
}
Output:
{(1, 3), (1, 4), (2, 3), (2, 4)}
{(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)}

C++

#include <iostream>
#include <vector>
#include <algorithm>

void print(const std::vector<std::vector<int>>& v) {
  std::cout << "{ ";
  for (const auto& p : v) {
    std::cout << "(";
    for (const auto& e : p) {
      std::cout << e << " ";
    }
    std::cout << ") ";
  }
  std::cout << "}" << std::endl;
}

auto product(const std::vector<std::vector<int>>& lists) {
  std::vector<std::vector<int>> result;
  if (std::find_if(std::begin(lists), std::end(lists), 
    [](auto e) -> bool { return e.size() == 0; }) != std::end(lists)) {
    return result;
  }
  for (auto& e : lists[0]) {
    result.push_back({ e });
  }
  for (size_t i = 1; i < lists.size(); ++i) {
    std::vector<std::vector<int>> temp;
    for (auto& e : result) {
      for (auto f : lists[i]) {
        auto e_tmp = e;
        e_tmp.push_back(f);
        temp.push_back(e_tmp);
      }
    }
    result = temp;
  }
  return result;
}

int main() {
  std::vector<std::vector<int>> prods[] = {
    { { 1, 2 }, { 3, 4 } },
    { { 3, 4 }, { 1, 2} },
    { { 1, 2 }, { } },
    { { }, { 1, 2 } },
    { { 1776, 1789 }, { 7, 12 }, { 4, 14, 23 }, { 0, 1 } },
    { { 1, 2, 3 }, { 30 }, { 500, 100 } },
    { { 1, 2, 3 }, { }, { 500, 100 } }
  };
  for (const auto& p : prods) {
    print(product(p));
  }
  std::cin.ignore();
  std::cin.get();
  return 0;
}
Output:
{ (1 3) (1 4) (2 3) (2 4) }
{ (3 1) (3 2) (4 1) (4 2) }
{ }
{ }
{ (1776 7 4 0) (1776 7 4 1) (1776 7 14 0) (1776 7 14 1) (1776 7 23 0) (1776 7 23 1) (1776 12 4 0) (1776 12 4 1) (1776 12 14 0) (1776 12 14 1) (1776 12 23 0) (1776 12 23 1) (1789 7 4 0) (1789 7 4 1) (1789 7 14 0) (1789 7 14 1) (1789 7 23 0) (1789 7 23 1) (1789 12 4 0) (1789 12 4 1) (1789 12 14 0) (1789 12 14 1) (1789 12 23 0) (1789 12 23 1) }
{ (1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100) }
{ }

Clojure

 (ns clojure.examples.product
	(:gen-class)
	(:require [clojure.pprint :as pp]))

(defn cart [colls]
  "Compute the cartesian product of list of lists"
  (if (empty? colls)
    '(())
    (for [more (cart (rest colls))
          x (first colls)]
      (cons x more))))

Output

(doseq [lst [   [[1,2],[3,4]], 
                [[3,4],[1,2]], [[], [1, 2]], 
                [[1, 2], []],
                [[1776, 1789],  [7, 12], [4, 14, 23], [0, 1]],
                [[1, 2, 3], [30,], [500, 100]],
                [[1, 2, 3], [], [500, 100]]
            ]
        ]
    (println lst "=>")
    (pp/pprint (cart lst)))
[[1 2] [3 4]] =>
((1 3) (2 3) (1 4) (2 4))
[[3 4] [1 2]] =>
((3 1) (4 1) (3 2) (4 2))
[[] [1 2]] =>
()
[[1 2] []] =>
()
[[1776 1789] [7 12] [4 14 23] [0 1]] =>
((1776 7 4 0)
 (1789 7 4 0)
 (1776 12 4 0)
 (1789 12 4 0)
 (1776 7 14 0)
 (1789 7 14 0)
 (1776 12 14 0)
 (1789 12 14 0)
 (1776 7 23 0)
 (1789 7 23 0)
 (1776 12 23 0)
 (1789 12 23 0)
 (1776 7 4 1)
 (1789 7 4 1)
 (1776 12 4 1)
 (1789 12 4 1)
 (1776 7 14 1)
 (1789 7 14 1)
 (1776 12 14 1)
 (1789 12 14 1)
 (1776 7 23 1)
 (1789 7 23 1)
 (1776 12 23 1)
 (1789 12 23 1))
[[1 2 3] [30] [500 100]] =>
((1 30 500) (2 30 500) (3 30 500) (1 30 100) (2 30 100) (3 30 100))
[[1 2 3] [] [500 100]] =>
()

Common Lisp

(defun cartesian-product (s1 s2)
  "Compute the cartesian product of two sets represented as lists"
  (loop for x in s1
	nconc (loop for y in s2 collect (list x y))))

Output

CL-USER> (cartesian-product '(1 2) '(3 4))
((1 3) (1 4) (2 3) (2 4))
CL-USER> (cartesian-product '(3 4) '(1 2))
((3 1) (3 2) (4 1) (4 2))
CL-USER> (cartesian-product '(1 2) '())
NIL
CL-USER> (cartesian-product '() '(1 2))
NIL

Extra credit:

(defun n-cartesian-product (l)
  "Compute the n-cartesian product of a list of sets (each of them represented as list).
   Algorithm:
     If there are no sets, then produce an empty set of tuples;
     otherwise, for all the elements x of the first set, concatenate the sets obtained by
     inserting x at the beginning of each tuple of the n-cartesian product of the remaining sets."
  (if (null l)
      (list nil)
      (loop for x in (car l)
            nconc (loop for y in (n-cartesian-product (cdr l))  
                        collect (cons x y)))))

Output:

CL-USER> (n-cartesian-product '((1776 1789) (7 12) (4 14 23) (0 1)))
((1776 7 4 0) (1776 7 4 1) (1776 7 14 0) (1776 7 14 1) (1776 7 23 0) (1776 7 23 1) (1776 12 4 0) (1776 12 4 1) (1776 12 14 0) (1776 12 14 1) (1776 12 23 0) (1776 12 23 1) (1789 7 4 0) (1789 7 4 1) (1789 7 14 0) (1789 7 14 1) (1789 7 23 0) (1789 7 23 1) (1789 12 4 0) (1789 12 4 1) (1789 12 14 0) (1789 12 14 1) (1789 12 23 0) (1789 12 23 1))
CL-USER> (n-cartesian-product '((1 2 3) (30) (500 100)))
((1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100))
CL-USER> (n-cartesian-product '((1 2 3) () (500 100)))
NIL

Crystal

The first function is the basic task. The version overloaded for one argument is the extra credit task, implemented using recursion.

def cartesian_product(a, b)
    return a.flat_map { |i| b.map { |j| [i, j] } }
end


def cartesian_product(l)
    if l.size <= 1
        return l
    elsif l.size == 2
        return cartesian_product(l[0], l[1])
    end

    return l[0].flat_map { |i| 
        cartesian_product(l[1..]).map { |j|
            [i, j].flatten
        }
    }
end


tests = [ [[1, 2], [3, 4]],
          [[3, 4], [1, 2]],
          [[1, 2], [] of Int32],
          [[] of Int32, [1, 2]],
          [[1, 2, 3], [30], [500, 100]],
          [[1, 2, 3], [] of Int32, [500, 100]],
          [[1776, 1789], [7, 12], [4, 14, 23], [0, 1]] ]

tests.each { |test|
    puts "#{test.join(" x ")} ->"
    puts "    #{cartesian_product(test)}"
    puts ""
}
Output:
[1, 2] x [3, 4] ->
    [[1, 3], [1, 4], [2, 3], [2, 4]]

[3, 4] x [1, 2] ->
    [[3, 1], [3, 2], [4, 1], [4, 2]]

[1, 2] x [] ->
    []

[] x [1, 2] ->
    []

[1, 2, 3] x [30] x [500, 100] ->
    [[1, 30, 500], [1, 30, 100], [2, 30, 500], [2, 30, 100], [3, 30, 500], [3, 30, 100]]

[1, 2, 3] x [] x [500, 100] ->
    []

[1776, 1789] x [7, 12] x [4, 14, 23] x [0, 1] ->
    [[1776, 7, 4, 0], [1776, 7, 4, 1], [1776, 7, 14, 0], [1776, 7, 14, 1], [1776, 7, 23, 0], [1776, 7, 23, 1], [1776, 12, 4, 0], [1776, 12, 4, 1], [1776, 12, 14, 0], [1776, 12, 14, 1], [1776, 12, 23, 0], [1776, 12, 23, 1], [1789, 7, 4, 0], [1789, 7, 4, 1], [1789, 7, 14, 0], [1789, 7, 14, 1], [1789, 7, 23, 0], [1789, 7, 23, 1], [1789, 12, 4, 0], [1789, 12, 4, 1], [1789, 12, 14, 0], [1789, 12, 14, 1], [1789, 12, 23, 0], [1789, 12, 23, 1]]

D

import std.stdio;

void main() {
    auto a = listProduct([1,2], [3,4]);
    writeln(a);

    auto b = listProduct([3,4], [1,2]);
    writeln(b);

    auto c = listProduct([1,2], []);
    writeln(c);

    auto d = listProduct([], [1,2]);
    writeln(d);
}

auto listProduct(T)(T[] ta, T[] tb) {
    struct Result {
        int i, j;

        bool empty() {
            return i>=ta.length
                || j>=tb.length;
        }

        T[] front() {
            return [ta[i], tb[j]];
        }

        void popFront() {
            if (++j>=tb.length) {
                j=0;
                i++;
            }
        }
    }

    return Result();
}
Output:
[[1, 3], [1, 4], [2, 3], [2, 4]]
[[3, 1], [3, 2], [4, 1], [4, 2]]
[]
[]

Delphi

Translation of: Go
program Cartesian_product_of_two_or_more_lists;

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

type
  TList = TArray<Integer>;

  TLists = TArray<TList>;

  TListHelper = record helper for TList
    function ToString: string;
  end;

  TListsHelper = record helper for TLists
    function ToString(BreakLines: boolean = false): string;
  end;

function cartN(arg: TLists): TLists;
var
  b, n: TList;
  argc: Integer;
begin
  argc := length(arg);

  var c := 1;
  for var a in arg do
    c := c * length(a);

  if c = 0 then
    exit;

  SetLength(result, c);
  SetLength(b, c * argc);
  SetLength(n, argc);

  var s := 0;
  for var i := 0 to c - 1 do
  begin
    var e := s + argc;
    var Resi := copy(b, s, e - s);
    Result[i] := Resi;

    s := e;
    for var j := 0 to high(n) do
    begin
      var nj := n[j];
      Resi[j] := arg[j, nj];
    end;

    for var j := high(n) downto 0 do
    begin
      inc(n[j]);
      if n[j] < Length(arg[j]) then
        Break;
      n[j] := 0;
    end;
  end;
end;

{ TListHelper }

function TListHelper.ToString: string;
begin
  Result := '[';
  for var i := 0 to High(self) do
  begin
    Result := Result + self[i].ToString;
    if i < High(self) then
      Result := Result + ' ';
  end;
  Result := Result + ']';
end;

{ TListsHelper }

function TListsHelper.ToString(BreakLines: boolean = false): string;
begin
  Result := '[';
  for var i := 0 to High(self) do
  begin
    Result := Result + self[i].ToString;
    if i < High(self) then
    begin
      if BreakLines then
        Result := Result + #10
      else
        Result := Result + ' ';
    end;
  end;
  Result := Result + ']';
end;

begin
  writeln(#10, cartN([[1, 2], [3, 4]]).ToString);
  writeln(#10, cartN([[3, 4], [1, 2]]).ToString);
  writeln(#10, cartN([[1, 2], []]).ToString);
  writeln(#10, cartN([[], [1, 2]]).ToString);

  writeln(#10, cartN([[1776, 1789], [17, 12], [4, 14, 23], [0, 1]]).ToString(True));

  writeln(#10, cartN([[1, 2, 3], [30], [500, 100]]).ToString);

  writeln(#10, cartN([[1, 2, 3], [], [500, 100]]).ToString);

  {$IFNDEF UNIX} readln; {$ENDIF}
end.
Output:
[[1 3] [1 4] [2 3] [2 4]]

[[3 1] [3 2] [4 1] [4 2]]

[]

[]

[[1776 17 4 0]
[1776 17 4 1]
[1776 17 14 0]
[1776 17 14 1]
[1776 17 23 0]
[1776 17 23 1]
[1776 12 4 0]
[1776 12 4 1]
[1776 12 14 0]
[1776 12 14 1]
[1776 12 23 0]
[1776 12 23 1]
[1789 17 4 0]
[1789 17 4 1]
[1789 17 14 0]
[1789 17 14 1]
[1789 17 23 0]
[1789 17 23 1]
[1789 12 4 0]
[1789 12 4 1]
[1789 12 14 0]
[1789 12 14 1]
[1789 12 23 0]
[1789 12 23 1]]

[[1 30 500] [1 30 100] [2 30 500] [2 30 100] [3 30 500] [3 30 100]]

[]

EasyLang

Translation of: Go
proc cart2 a[] b[] . p[][] .
   p[][] = [ ]
   for a in a[]
      for b in b[]
         p[][] &= [ a b ]
      .
   .
.
cart2 [ 1 2 ] [ 3 4 ] r[][]
print r[][]
cart2 [ 3 4 ] [ 1 2 ] r[][]
print r[][]
cart2 [ 1 2 ] [ ] r[][]
print r[][]
cart2 [ ] [ 1 2 ] r[][]
print r[][]

Erlang

Can do this with list comprehensions.

-module(cartesian).
-export([product/2]).

product(S1, S2) -> [{A,B} || A <- S1, B <- S2].
Output:
2> cartesian:product([],[1,2,3]).
[]
3> cartesian:product([1,2,3],[]).
[]
4> cartesian:product([1,2],[3,4]).
[{1,3},{1,4},{2,3},{2,4}]
5> cartesian:product([3,4],[1,2]).
[{3,1},{3,2},{4,1},{4,2}]

F#

The Task

//Nigel Galloway February 12th., 2018
let cP2 n g = List.map (fun (n,g)->[n;g]) (List.allPairs n g)
Output:
cP2 [1;2] [3;4] -> [[1; 3]; [1; 4]; [2; 3]; [2; 4]]
cP2 [3;4] [1;2] -> [[3; 1]; [3; 2]; [4; 1]; [4; 2]]
cP2 [1;2] []    -> []
cP2 [] [1;2]    -> []

Extra Credit

//Nigel Galloway August 14th., 2018
let cP ng=Seq.foldBack(fun n g->[for n' in n do for g' in g do yield n'::g']) ng [[]]
Output:
cP [[1;2];[3;4]] -> [[1; 3]; [1; 4]; [2; 3]; [2; 4]]
cP [[3;4];[1;2]] -> [[3; 1]; [3; 2]; [4; 1]; [4; 2]]
cP [[3;4];[]] ->[]
cP [[];[1;2]] ->[]
cP [[1776;1789];[7;12];[4;14;23];[0;1]] -> [[1776; 7; 4; 0]; [1776; 7; 4; 1]; [1776; 7; 14; 0]; [1776; 7; 14; 1];
                                            [1776; 7; 23; 0]; [1776; 7; 23; 1]; [1776; 12; 4; 0]; [1776; 12; 4; 1];
                                            [1776; 12; 14; 0]; [1776; 12; 14; 1]; [1776; 12; 23; 0]; [1776; 12; 23; 1];
                                            [1789; 7; 4; 0]; [1789; 7; 4; 1]; [1789; 7; 14; 0]; [1789; 7; 14; 1];
                                            [1789; 7; 23; 0]; [1789; 7; 23; 1]; [1789; 12; 4; 0]; [1789; 12; 4; 1];                                                                                                        
                                            [1789; 12; 14; 0]; [1789; 12; 14; 1]; [1789; 12; 23; 0]; [1789; 12; 23; 1]]
cP [[1;2;3];[30];[500;100]] -> [[1; 30; 500]; [1; 30; 100]; [2; 30; 500]; [2; 30; 100]; [3; 30; 500]; [3; 30; 100]]
cP [[1;2;3];[];[500;100]] -> []

Factor

IN: scratchpad { 1 2 } { 3 4 } cartesian-product .
{ { { 1 3 } { 1 4 } } { { 2 3 } { 2 4 } } }
IN: scratchpad { 3 4 } { 1 2 } cartesian-product .
{ { { 3 1 } { 3 2 } } { { 4 1 } { 4 2 } } }
IN: scratchpad { 1 2 } { } cartesian-product .
{ { } { } }
IN: scratchpad { } { 1 2 } cartesian-product .
{ }

Fortran

This implementation is hard to extend to n-ary products but it is simple and works well for binary products of lists of any length.

 ! Created by simon on 29/04/2021.
  
 ! ifort -o cartesian_product cartesian_product.f90 -check all
 
 module tuple
    implicit none
    private
    public :: tuple_t, operator(*), print
 
    type tuple_t(n)
        integer, len     :: n
        integer, private :: v(n)
    contains
        procedure, public :: print => print_tuple_t
        generic, public :: assignment(=) => eq_tuple_t
        procedure, public :: eq_tuple_t
    end type tuple_t
 
    interface print
        module procedure print_tuple_a_t
    end interface print
    interface operator(*)
        module procedure tup_times_tup
    end interface
 
 contains
    subroutine eq_tuple_t(this, src)
        class(tuple_t(*)), intent(inout) :: this
        integer, intent(in)              :: src(:)
        this%v = src
    end subroutine eq_tuple_t

    pure function tup_times_tup(a, b) result(r)
        type(tuple_t(*)), intent(in)  :: a
        type(tuple_t(*)), intent(in)  :: b
        type(tuple_t(2)), allocatable :: r(:)
        integer :: i, j, k
 
        allocate(r(a%n*b%n))
        k = 0
        do i=1,a%n
            do j=1,b%n
                k = k + 1
                r(k)%v = [a%v(i),b%v(j)]
            end do
        end do
    end function tup_times_tup
 
    subroutine print_tuple_t(this)
        class(tuple_t(*)), intent(in) :: this
        integer :: i
        write(*,fmt='(a)',advance='no') '{'
        do i=1,size(this%v)
            write(*,fmt='(i0)',advance='no') this%v(i)
            if (i < size(this%v)) write(*,fmt='(a)',advance='no') ','
        end do
        write(*,fmt='(a)',advance='no') '}'
    end subroutine print_tuple_t
 
    subroutine print_tuple_a_t(r)
        type(tuple_t(*)), intent(in) :: r(:)
        integer :: i
        write(*,fmt='(a)',advance='no') '{'
        do i=1,size(r)
            call r(i)%print
            if (i < size(r)) write(*,fmt='(a)',advance='no') ','
        end do
        write(*,fmt='(a)') '}'
    end subroutine print_tuple_a_t
 end module tuple
 
 program cartesian_product
    use tuple
 
    implicit none
    type(tuple_t(2)) :: a, b
    type(tuple_t(0)) :: z
 
    a = [1,2]
    b = [3,4]
 
    call print_product(a, b)
    call print_product(b, a)
    call print_product(z, a)
    call print_product(a, z)
 
    stop
 contains
    subroutine print_product(s, t)
        type(tuple_t(*)), intent(in) :: s
        type(tuple_t(*)), intent(in) :: t
        call s%print
        write(*,fmt='(a)',advance='no') ' x '
        call t%print
        write(*,fmt='(a)',advance='no') ' = '
        call print(s*t)
    end subroutine print_product
 end program cartesian_product
Output:
 {1,2} x {3,4} = {{1,3},{1,4},{2,3},{2,4}}
 {3,4} x {1,2} = {{3,1},{3,2},{4,1},{4,2}}
 {1,2} x {} = {}
 {} x {1,2} = {}

FreeBASIC

I'll leave the extra credit part for someone else. It's just going to amount to repeatedly finding Cartesian products and flattening the result, so considerably less interesting than Cartesian products where the list items themselves can be lists.

#define MAXLEN 64

type listitem                  ' An item of a list may be a number
    is_num as boolean       ' or another list, so I have to account
    union                      ' for both, implemented as a union.
        list as any ptr        ' FreeBASIC is twitchy about circularly
        num as uinteger        ' defined types, so one workaround is to
    end union                  ' use a generic pointer that I will cast
end type                       ' later.

type list
    length as uinteger              'simple, fixed storage length lists
    item(1 to MAXLEN) as listitem   'are good enough for this example
end type

sub print_list( list as list )
    print "{";
    if list.length = 0 then print "}"; : return
    for i as uinteger = 1 to list.length
        if list.item(i).is_num then
            print str(list.item(i).num);
        else     'recursively print sublist
            print_list( *cast(list ptr, list.item(i).list) )
        end if
    if i<list.length then print ", "; else print "}";   'handle comma
    next i                                              'gracefully
    return
end sub

function cartprod( A as list, B as list ) as list
    dim as uinteger i, j
    dim as list C
    dim as list ptr inner  'for brevity
    C.length = 0
    for i = 1 to A.length
        for j = 1 to B.length
            C.length += 1
            C.item(C.length).is_num = false   'each item of the new list is a list itself
            inner = allocate( sizeof(list) )     'make space for it
            C.item(C.length).list = inner
            inner->length = 2                    'each inner list contains two items
            inner->item(1) = A.item(i)           'one from the first list
            inner->item(2) = B.item(j)           'and one from the second
        next j
    next i
    return C
end function

dim as list EMPTY, A, B, R
EMPTY.length = 0
A.length = 2 
A.item(1).is_num = true : A.item(1).num = 1
A.item(2).is_num = true : A.item(2).num = 2
B.length = 2 
B.item(1).is_num = true : B.item(1).num = 3
B.item(2).is_num = true : B.item(2).num = 4

R = cartprod(A, B)
print_list(R) : print   'print_list does not supply a final newline
R = cartprod(B, A) : print_list(R) : print
R = cartprod(A, EMPTY) : print_list(R) : print
R = cartprod(EMPTY, A) : print_list(R) : print
Output:
{{1, 3}, {1, 4}, {2, 3}, {2, 4}}

{{3, 1}, {3, 2}, {4, 1}, {4, 2}} {} {}

Fōrmulæ

Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.

Programs in Fōrmulæ are created/edited online in its website.

In this page you can see and run the program(s) related to this task and their results. You can also change either the programs or the parameters they are called with, for experimentation, but remember that these programs were created with the main purpose of showing a clear solution of the task, and they generally lack any kind of validation.

Solution

No program is needed, the cartesian product is an intrinsic operation in Fōrmulæ

Test case 1. No commutativity

Test case 2. With an empty list

Test case 3. Extra credit. n-ary cartesian product

Go

Basic Task

package main

import "fmt"

type pair [2]int

func cart2(a, b []int) []pair {
    p := make([]pair, len(a)*len(b))
    i := 0
    for _, a := range a {
        for _, b := range b {
            p[i] = pair{a, b}
            i++
        }
    }
    return p
}

func main() {
    fmt.Println(cart2([]int{1, 2}, []int{3, 4}))
    fmt.Println(cart2([]int{3, 4}, []int{1, 2}))
    fmt.Println(cart2([]int{1, 2}, nil))
    fmt.Println(cart2(nil, []int{1, 2}))
}
Output:
[[1 3] [1 4] [2 3] [2 4]]
[[3 1] [3 2] [4 1] [4 2]]
[]
[]

Extra credit 1

This solution minimizes allocations and computes and fills the result sequentially.

package main

import "fmt"

func cartN(a ...[]int) [][]int {
    c := 1
    for _, a := range a {
        c *= len(a)
    }
    if c == 0 {
        return nil
    }
    p := make([][]int, c)
    b := make([]int, c*len(a))
    n := make([]int, len(a))
    s := 0
    for i := range p {
        e := s + len(a)
        pi := b[s:e]
        p[i] = pi
        s = e
        for j, n := range n {
            pi[j] = a[j][n]
        }
        for j := len(n) - 1; j >= 0; j-- {
            n[j]++
            if n[j] < len(a[j]) {
                break
            }
            n[j] = 0
        }
    }
    return p
}

func main() {
    fmt.Println(cartN([]int{1, 2}, []int{3, 4}))
    fmt.Println(cartN([]int{3, 4}, []int{1, 2}))
    fmt.Println(cartN([]int{1, 2}, nil))
    fmt.Println(cartN(nil, []int{1, 2}))

    fmt.Println()
    fmt.Println("[")
    for _, p := range cartN(
        []int{1776, 1789},
        []int{7, 12},
        []int{4, 14, 23},
        []int{0, 1},
    ) {
        fmt.Println(" ", p)
    }
    fmt.Println("]")
    fmt.Println(cartN([]int{1, 2, 3}, []int{30}, []int{500, 100}))
    fmt.Println(cartN([]int{1, 2, 3}, []int{}, []int{500, 100}))

    fmt.Println()
    fmt.Println(cartN(nil))
    fmt.Println(cartN())
}
Output:
[[1 3] [1 4] [2 3] [2 4]]
[[3 1] [3 2] [4 1] [4 2]]
[]
[]

[
  [1776 7 4 0]
  [1776 7 4 1]
  [1776 7 14 0]
  [1776 7 14 1]
  [1776 7 23 0]
  [1776 7 23 1]
  [1776 12 4 0]
  [1776 12 4 1]
  [1776 12 14 0]
  [1776 12 14 1]
  [1776 12 23 0]
  [1776 12 23 1]
  [1789 7 4 0]
  [1789 7 4 1]
  [1789 7 14 0]
  [1789 7 14 1]
  [1789 7 23 0]
  [1789 7 23 1]
  [1789 12 4 0]
  [1789 12 4 1]
  [1789 12 14 0]
  [1789 12 14 1]
  [1789 12 23 0]
  [1789 12 23 1]
]
[[1 30 500] [1 30 100] [2 30 500] [2 30 100] [3 30 500] [3 30 100]]
[]

[]
[[]]

Extra credit 2

Code here is more compact, but with the cost of more garbage produced. It produces the same result as cartN above.

func cartN(a ...[]int) (c [][]int) {
    if len(a) == 0 {
        return [][]int{nil}
    }
    r := cartN(a[1:]...)
    for _, e := range a[0] {
        for _, p := range r {
            c = append(c, append([]int{e}, p...))
        }
    }
    return
}

Extra credit 3

This is a compact recursive version like Extra credit 2 but the result list is ordered differently. This is still a correct result if you consider a cartesian product to be a set, which is an unordered collection. Note that the set elements are still ordered lists. A cartesian product is an unordered collection of ordered collections. It draws attention though to the gloss of using list representations as sets. Any of the functions here will accept duplicate elements in the input lists, and then produce duplicate elements in the result.

func cartN(a ...[]int) (c [][]int) {
    if len(a) == 0 {
        return [][]int{nil}
    }
    last := len(a) - 1
    l := cartN(a[:last]...)
    for _, e := range a[last] {
        for _, p := range l {
            c = append(c, append(p, e))
        }
    }
    return
}

Groovy

Solution:
The following CartesianCategory class allows for modification of regular Iterable interface behavior, overloading Iterable's multiply (*) operator to perform a Cartesian Product when the second operand is also an Iterable.

class CartesianCategory {
    static Iterable multiply(Iterable a, Iterable b) {
        assert [a,b].every { it != null }
        def (m,n) = [a.size(),b.size()]
        (0..<(m*n)).inject([]) { prod, i -> prod << [a[i.intdiv(n)], b[i%n]].flatten() }
    }
}

Test:
The mixin method call is necessary to make the multiply (*) operator work.

Iterable.metaClass.mixin CartesianCategory

println "\nCore Solution:"
println "[1, 2] × [3, 4] = ${[1, 2] * [3, 4]}"
println "[3, 4] × [1, 2] = ${[3, 4] * [1, 2]}"
println "[1, 2] × [] = ${[1, 2] * []}"
println "[] × [1, 2] = ${[] * [1, 2]}"

println "\nExtra Credit:"
println "[1776, 1789] × [7, 12] × [4, 14, 23] × [0, 1] = ${[1776, 1789] * [7, 12] * [4, 14, 23] * [0, 1]}"
println "[1, 2, 3] × [30] × [500, 100] = ${[1, 2, 3] * [30] * [500, 100]}"
println "[1, 2, 3] × [] × [500, 100] = ${[1, 2, 3] * [] * [500, 100]}"

println "\nNon-Numeric Example:"
println "[John,Paul,George,Ringo] × [Emerson,Lake,Palmer] × [Simon,Garfunkle] = ["
( ["John","Paul","George","Ringo"] * ["Emerson","Lake","Palmer"] * ["Simon","Garfunkle"] ).each { println "\t${it}," }
println "]"

Output:

Core Solution:
[1, 2] × [3, 4] = [[1, 3], [1, 4], [2, 3], [2, 4]]
[3, 4] × [1, 2] = [[3, 1], [3, 2], [4, 1], [4, 2]]
[1, 2] × [] = []
[] × [1, 2] = []

Extra Credit:
[1776, 1789] × [7, 12] × [4, 14, 23] × [0, 1] = [[1776, 7, 4, 0], [1776, 7, 4, 1], [1776, 7, 14, 0], [1776, 7, 14, 1], [1776, 7, 23, 0], [1776, 7, 23, 1], [1776, 12, 4, 0], [1776, 12, 4, 1], [1776, 12, 14, 0], [1776, 12, 14, 1], [1776, 12, 23, 0], [1776, 12, 23, 1], [1789, 7, 4, 0], [1789, 7, 4, 1], [1789, 7, 14, 0], [1789, 7, 14, 1], [1789, 7, 23, 0], [1789, 7, 23, 1], [1789, 12, 4, 0], [1789, 12, 4, 1], [1789, 12, 14, 0], [1789, 12, 14, 1], [1789, 12, 23, 0], [1789, 12, 23, 1]]
[1, 2, 3] × [30] × [500, 100] = [[1, 30, 500], [1, 30, 100], [2, 30, 500], [2, 30, 100], [3, 30, 500], [3, 30, 100]]
[1, 2, 3] × [] × [500, 100] = []

Non-Numeric Example:
[John,Paul,George,Ringo] × [Emerson,Lake,Palmer] × [Simon,Garfunkle] = [
	[John, Emerson, Simon],
	[John, Emerson, Garfunkle],
	[John, Lake, Simon],
	[John, Lake, Garfunkle],
	[John, Palmer, Simon],
	[John, Palmer, Garfunkle],
	[Paul, Emerson, Simon],
	[Paul, Emerson, Garfunkle],
	[Paul, Lake, Simon],
	[Paul, Lake, Garfunkle],
	[Paul, Palmer, Simon],
	[Paul, Palmer, Garfunkle],
	[George, Emerson, Simon],
	[George, Emerson, Garfunkle],
	[George, Lake, Simon],
	[George, Lake, Garfunkle],
	[George, Palmer, Simon],
	[George, Palmer, Garfunkle],
	[Ringo, Emerson, Simon],
	[Ringo, Emerson, Garfunkle],
	[Ringo, Lake, Simon],
	[Ringo, Lake, Garfunkle],
	[Ringo, Palmer, Simon],
	[Ringo, Palmer, Garfunkle],
]

Haskell

Various routes can be taken to Cartesian products in Haskell. For the product of two lists we could write:

cartProd :: [a] -> [b] -> [(a, b)]
cartProd xs ys =
  [ (x, y)
  | x <- xs 
  , y <- ys ]

more directly:

cartProd :: [a] -> [b] -> [(a, b)]
cartProd xs ys = xs >>= \x -> ys >>= \y -> [(x, y)]

applicatively:

cartProd :: [a] -> [b] -> [(a, b)]
cartProd xs ys = (,) <$> xs <*> ys

parsimoniously:

cartProd :: [a] -> [b] -> [(a, b)]
cartProd = (<*>) . fmap (,)

We might test any of these with:

main :: IO ()
main =
  mapM_ print $
  uncurry cartProd <$>
  [([1, 2], [3, 4]), ([3, 4], [1, 2]), ([1, 2], []), ([], [1, 2])]
Output:
[(1,3),(1,4),(2,3),(2,4)]
[(3,1),(3,2),(4,1),(4,2)]
[]
[]


For the n-ary Cartesian product of an arbitrary number of lists, we could apply the Prelude's standard sequence function to a list of lists,

cartProdN :: [[a]] -> [[a]]
cartProdN = sequence

main :: IO ()
main = print $ cartProdN [[1, 2], [3, 4], [5, 6]]
Output:
[[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]]

or we could define ourselves an equivalent function over a list of lists in terms of a fold, for example as:

cartProdN :: [[a]] -> [[a]]
cartProdN = foldr (\xs as -> xs >>= (<$> as) . (:)) [[]]

or, equivalently, as:

cartProdN :: [[a]] -> [[a]]
cartProdN = foldr
    (\xs as ->
        [ x : a
        | x <- xs
        , a <- as ])
    [[]]

testing any of these with something like:

main :: IO ()
main = do
  mapM_ print $ 
    cartProdN [[1776, 1789], [7,12], [4, 14, 23], [0,1]]
  putStrLn ""
  print $ cartProdN [[1,2,3], [30], [500, 100]]
  putStrLn ""
  print $ cartProdN [[1,2,3], [], [500, 100]]
Output:
[1776,7,4,0]
[1776,7,4,1]
[1776,7,14,0]
[1776,7,14,1]
[1776,7,23,0]
[1776,7,23,1]
[1776,12,4,0]
[1776,12,4,1]
[1776,12,14,0]
[1776,12,14,1]
[1776,12,23,0]
[1776,12,23,1]
[1789,7,4,0]
[1789,7,4,1]
[1789,7,14,0]
[1789,7,14,1]
[1789,7,23,0]
[1789,7,23,1]
[1789,12,4,0]
[1789,12,4,1]
[1789,12,14,0]
[1789,12,14,1]
[1789,12,23,0]
[1789,12,23,1]

[[1,30,500],[1,30,100],[2,30,500],[2,30,100],[3,30,500],[3,30,100]]

[]

J

The J primitive catalogue { forms the Cartesian Product of two or more boxed lists. The result is a multi-dimensional array (which can be reshaped to a simple list of lists if desired).

   { 1776 1789 ; 7 12 ; 4 14 23 ; 0 1   NB. result is 4 dimensional array with shape 2 2 3 2
┌────────────┬────────────┐
1776 7 4 0  1776 7 4 1  
├────────────┼────────────┤
1776 7 14 0 1776 7 14 1 
├────────────┼────────────┤
1776 7 23 0 1776 7 23 1 
└────────────┴────────────┘

┌────────────┬────────────┐
1776 12 4 0 1776 12 4 1 
├────────────┼────────────┤
1776 12 14 01776 12 14 1
├────────────┼────────────┤
1776 12 23 01776 12 23 1
└────────────┴────────────┘


┌────────────┬────────────┐
1789 7 4 0  1789 7 4 1  
├────────────┼────────────┤
1789 7 14 0 1789 7 14 1 
├────────────┼────────────┤
1789 7 23 0 1789 7 23 1 
└────────────┴────────────┘

┌────────────┬────────────┐
1789 12 4 0 1789 12 4 1 
├────────────┼────────────┤
1789 12 14 01789 12 14 1
├────────────┼────────────┤
1789 12 23 01789 12 23 1
└────────────┴────────────┘
   { 1 2 3 ; 30 ; 50 100    NB. result is a 2-dimensional array with shape 2 3
┌───────┬────────┐
1 30 501 30 100
├───────┼────────┤
2 30 502 30 100
├───────┼────────┤
3 30 503 30 100
└───────┴────────┘
   { 1 2 3 ; '' ; 50 100    NB. result is an empty 3-dimensional array with shape 3 0 2

Java

Works with: Java Virtual Machine version 1.8
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Optional.of;
import static java.util.stream.Collectors.toList;

import java.util.List;

public class CartesianProduct {

    public List<?> product(List<?>... a) {
        if (a.length >= 2) {
            List<?> product = a[0];
            for (int i = 1; i < a.length; i++) {
                product = product(product, a[i]);
            }
            return product;
        }

        return emptyList();
    }

    private <A, B> List<?> product(List<A> a, List<B> b) {
        return of(a.stream()
                .map(e1 -> of(b.stream().map(e2 -> asList(e1, e2)).collect(toList())).orElse(emptyList()))
                .flatMap(List::stream)
                .collect(toList())).orElse(emptyList());
    }
}

Using a generic class with a recursive function

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CartesianProduct<V> {

	public List<List<V>> product(List<List<V>> lists) {
		List<List<V>> product = new ArrayList<>();

		// We first create a list for each value of the first list
		product(product, new ArrayList<>(), lists);

		return product;
	}

	private void product(List<List<V>> result, List<V> existingTupleToComplete, List<List<V>> valuesToUse) {
		for (V value : valuesToUse.get(0)) {
			List<V> newExisting = new ArrayList<>(existingTupleToComplete);
			newExisting.add(value);

			// If only one column is left
			if (valuesToUse.size() == 1) {
				// We create a new list with the exiting tuple for each value with the value
				// added
				result.add(newExisting);
			} else {
				// If there are still several columns, we go into recursion for each value
				List<List<V>> newValues = new ArrayList<>();
				// We build the next level of values
				for (int i = 1; i < valuesToUse.size(); i++) {
					newValues.add(valuesToUse.get(i));
				}

				product(result, newExisting, newValues);
			}
		}
	}

	public static void main(String[] args) {
		List<Integer> list1 = new ArrayList<>(Arrays.asList(new Integer[] { 1776, 1789 }));
		List<Integer> list2 = new ArrayList<>(Arrays.asList(new Integer[] { 7, 12 }));
		List<Integer> list3 = new ArrayList<>(Arrays.asList(new Integer[] { 4, 14, 23 }));
		List<Integer> list4 = new ArrayList<>(Arrays.asList(new Integer[] { 0, 1 }));

		List<List<Integer>> input = new ArrayList<>();
		input.add(list1);
		input.add(list2);
		input.add(list3);
		input.add(list4);

		CartesianProduct<Integer> cartesianProduct = new CartesianProduct<>();
		List<List<Integer>> product = cartesianProduct.product(input);
		System.out.println(product);
	}
}

JavaScript

   function cartesian(m){
       if(!m.length)return[[]];
       let tails=cartesian(m.slice(1));
       return(m[0].flatMap(h=>tails.map(t=>[h].concat(t))));
   }

ES6

Functional

Cartesian products fall quite naturally out of concatMap (Array.flatMap), and its argument-flipped twin bind.

For the Cartesian product of just two lists:

(() => {
    // CARTESIAN PRODUCT OF TWO LISTS ---------------------

    // cartProd :: [a] -> [b] -> [[a, b]]
    const cartProd = xs => ys =>
        xs.flatMap(x => ys.map(y => [x, y]))


    // TEST -----------------------------------------------
    return [
        cartProd([1, 2])([3, 4]),
        cartProd([3, 4])([1, 2]),
        cartProd([1, 2])([]),
        cartProd([])([1, 2]),
    ].map(JSON.stringify).join('\n');
})();
Output:
[[1,3],[1,4],[2,3],[2,4]]
[[3,1],[3,2],[4,1],[4,2]]
[]
[]


Abstracting a little more, we can define the cartesian product quite economically in terms of a general applicative operator:

(() => {

    // CARTESIAN PRODUCT OF TWO LISTS ---------------------

    // cartesianProduct :: [a] -> [b] -> [(a, b)]
    const cartesianProduct = xs =>
        ap(xs.map(Tuple));


    // GENERIC FUNCTIONS ----------------------------------

    // e.g. [(*2),(/2), sqrt] <*> [1,2,3]
    // -->  ap([dbl, hlf, root], [1, 2, 3])
    // -->  [2,4,6,0.5,1,1.5,1,1.4142135623730951,1.7320508075688772]

    // Each member of a list of functions applied to each
    // of a list of arguments, deriving a list of new values.

    // ap (<*>) :: [(a -> b)] -> [a] -> [b]
    const ap = fs => xs =>
        // The sequential application of each of a list
        // of functions to each of a list of values.
        fs.flatMap(
            f => xs.map(f)
        );

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = a => b => [a, b];

    // TEST -----------------------------------------------
    return [
            cartesianProduct([1, 2])([3, 4]),
            cartesianProduct([3, 4])([1, 2]),
            cartesianProduct([1, 2])([]),
            cartesianProduct([])([1, 2]),
        ]
        .map(JSON.stringify)
        .join('\n');
})();
Output:
[[1,3],[1,4],[2,3],[2,4]]
[[3,1],[3,2],[4,1],[4,2]]
[]
[]

For the n-ary Cartesian product over a list of lists:

(() => {
    const main = () => {
        // n-ary Cartesian product of a list of lists.

        // cartProdN :: [[a]] -> [[a]]
        const cartProdN = foldr(
            xs => as =>
            bind(as)(
                x => bind(xs)(
                    a => [
                        [a].concat(x)
                    ]
                )
            )
        )([
            []
        ]);

        // TEST -------------------------------------------
        return intercalate('\n\n')([
            map(show)(
                cartProdN([
                    [1776, 1789],
                    [7, 12],
                    [4, 14, 23],
                    [0, 1]
                ])
            ).join('\n'),
            show(cartProdN([
                [1, 2, 3],
                [30],
                [50, 100]
            ])),
            show(cartProdN([
                [1, 2, 3],
                [],
                [50, 100]
            ]))
        ])
    };

    // GENERIC FUNCTIONS ----------------------------------

    // bind ::  [a] -> (a -> [b]) -> [b]
    const bind = xs => f => xs.flatMap(f);

    // foldr :: (a -> b -> b) -> b -> [a] -> b
    const foldr = f => a => xs =>
        xs.reduceRight((a, x) => f(x)(a), a);

    // intercalate :: String -> [a] -> String
    const intercalate = s => xs => xs.join(s);

    // map :: (a -> b) -> [a] -> [b]
    const map = f => xs => xs.map(f);

    // show :: a -> String
    const show = x => JSON.stringify(x);

    return main();
})();
Output:
[1776,7,4,0]
[1776,7,4,1]
[1776,7,14,0]
[1776,7,14,1]
[1776,7,23,0]
[1776,7,23,1]
[1776,12,4,0]
[1776,12,4,1]
[1776,12,14,0]
[1776,12,14,1]
[1776,12,23,0]
[1776,12,23,1]
[1789,7,4,0]
[1789,7,4,1]
[1789,7,14,0]
[1789,7,14,1]
[1789,7,23,0]
[1789,7,23,1]
[1789,12,4,0]
[1789,12,4,1]
[1789,12,14,0]
[1789,12,14,1]
[1789,12,23,0]
[1789,12,23,1]

[[1,30,50],[1,30,100],[2,30,50],[2,30,100],[3,30,50],[3,30,100]]

[]

Imperative

Imperative implementations of Cartesian products are inevitably less compact and direct, but we can certainly write an iterative translation of a fold over nested applications of bind or concatMap:

(() => {
    // n-ary Cartesian product of a list of lists
    // ( Imperative implementation )

    // cartProd :: [a] -> [b] -> [[a, b]]
    const cartProd = lists => {
        let ps = [],
            acc = [
                []
            ],
            i = lists.length;
        while (i--) {
            let subList = lists[i],
                j = subList.length;
            while (j--) {
                let x = subList[j],
                    k = acc.length;
                while (k--) ps.push([x].concat(acc[k]))
            };
            acc = ps;
            ps = [];
        };
        return acc.reverse();
    };

    // GENERIC FUNCTIONS ------------------------------------------------------

    // intercalate :: String -> [a] -> String
    const intercalate = (s, xs) => xs.join(s);

    // map :: (a -> b) -> [a] -> [b]
    const map = (f, xs) => xs.map(f);

    // show :: a -> String
    const show = x => JSON.stringify(x);

    // unlines :: [String] -> String
    const unlines = xs => xs.join('\n');

    // TEST -------------------------------------------------------------------
    return intercalate('\n\n', [show(cartProd([
            [1, 2],
            [3, 4]
        ])),
        show(cartProd([
            [3, 4],
            [1, 2]
        ])),
        show(cartProd([
            [1, 2],
            []
        ])),
        show(cartProd([
            [],
            [1, 2]
        ])),
        unlines(map(show, cartProd([
            [1776, 1789],
            [7, 12],
            [4, 14, 23],
            [0, 1]
        ]))),
        show(cartProd([
            [1, 2, 3],
            [30],
            [50, 100]
        ])),
        show(cartProd([
            [1, 2, 3],
            [],
            [50, 100]
        ]))
    ]);
})();
Output:
[[1,4],[1,3],[2,4],[2,3]]

[[3,2],[3,1],[4,2],[4,1]]

[]

[]

[1776,12,4,1]
[1776,12,4,0]
[1776,12,14,1]
[1776,12,14,0]
[1776,12,23,1]
[1776,12,23,0]
[1776,7,4,1]
[1776,7,4,0]
[1776,7,14,1]
[1776,7,14,0]
[1776,7,23,1]
[1776,7,23,0]
[1789,12,4,1]
[1789,12,4,0]
[1789,12,14,1]
[1789,12,14,0]
[1789,12,23,1]
[1789,12,23,0]
[1789,7,4,1]
[1789,7,4,0]
[1789,7,14,1]
[1789,7,14,0]
[1789,7,23,1]
[1789,7,23,0]

[[1,30,50],[1,30,100],[2,30,50],[2,30,100],[3,30,50],[3,30,100]]

[]

jq

jq is stream-oriented and so we begin by defining a function that will emit a stream of the elements of the Cartesian product of two arrays:

def products: .[0][] as $x | .[1][] as $y | [$x,$y];

To generate an array of these arrays, one would in practice most likely simply write `[products]`, but to comply with the requirements of this article, we can define `product` as:

def product: [products];

For the sake of brevity, two illustrations should suffice:

   [ [1,2], [3,4] ] | products

produces the stream:

 [1,3]
 [1,4]
 [2,3]
 [2,4]

And

[[1,2], []] | product

produces:

[]

n-way Cartesian Product

Given an array of two or more arrays as input, `cartesians` as defined here produces a stream of the components of their Cartesian product:

def cartesians:
  if length <= 2 then products
  else .[0][] as $x
  | (.[1:] | cartesians) as $y
  | [$x] + $y
  end;

Again for brevity, in the following, we will just show the number of items in the Cartesian products:

   [ [1776, 1789], [7, 12], [4, 14, 23], [0, 1]] | [cartesians] | length
   # 24
   [[1, 2, 3], [30], [500, 100] ] | [cartesians] | length
   # 6
   [[1, 2, 3], [], [500, 100] ] | [cartesians] | length
   # 0

Julia

Run in REPL.

# Product {1, 2} × {3, 4}
collect(Iterators.product([1, 2], [3, 4]))
# Product {3, 4} × {1, 2}
collect(Iterators.product([3, 4], [1, 2]))
 
# Product {1, 2} × {}
collect(Iterators.product([1, 2], []))
# Product {} × {1, 2}
collect(Iterators.product([], [1, 2]))
 
# Product {1776, 1789} × {7, 12} × {4, 14, 23} × {0, 1}
collect(Iterators.product([1776, 1789], [7, 12], [4, 14, 23], [0, 1]))
# Product {1, 2, 3} × {30} × {500, 100}
collect(Iterators.product([1, 2, 3], [30], [500, 100]))
# Product {1, 2, 3} × {} × {500, 100}
collect(Iterators.product([1, 2, 3], [], [500, 100]))

Kotlin

// version 1.1.2

fun flattenList(nestList: List<Any>): List<Any> {
    val flatList = mutableListOf<Any>()

    fun flatten(list: List<Any>) {
        for (e in list) {
            if (e !is List<*>)
                flatList.add(e)
            else
                @Suppress("UNCHECKED_CAST")
                flatten(e as List<Any>)
        }
    }

    flatten(nestList)
    return flatList
}

operator fun List<Any>.times(other: List<Any>): List<List<Any>> {
    val prod = mutableListOf<List<Any>>()
    for (e in this) {
        for (f in other) {
            prod.add(listOf(e, f))
        }
    }
    return prod
}

fun nAryCartesianProduct(lists: List<List<Any>>): List<List<Any>> {
    require(lists.size >= 2)
    return lists.drop(2).fold(lists[0] * lists[1]) { cp, ls -> cp * ls }.map { flattenList(it) }
}

fun printNAryProduct(lists: List<List<Any>>) {
    println("${lists.joinToString(" x ")} = ")
    println("[")
    println(nAryCartesianProduct(lists).joinToString("\n    ", "    "))
    println("]\n")
}

fun main(args: Array<String>) {
   println("[1, 2] x [3, 4] = ${listOf(1, 2) * listOf(3, 4)}")
   println("[3, 4] x [1, 2] = ${listOf(3, 4) * listOf(1, 2)}")
   println("[1, 2] x []     = ${listOf(1, 2) * listOf()}")
   println("[]     x [1, 2] = ${listOf<Any>() * listOf(1, 2)}")
   println("[1, a] x [2, b] = ${listOf(1, 'a') * listOf(2, 'b')}")
   println()
   printNAryProduct(listOf(listOf(1776, 1789), listOf(7, 12), listOf(4, 14, 23), listOf(0, 1)))
   printNAryProduct(listOf(listOf(1, 2, 3), listOf(30), listOf(500, 100)))
   printNAryProduct(listOf(listOf(1, 2, 3), listOf<Int>(), listOf(500, 100)))
   printNAryProduct(listOf(listOf(1, 2, 3), listOf(30), listOf('a', 'b')))
}
Output:
[1, 2] x [3, 4] = [[1, 3], [1, 4], [2, 3], [2, 4]]
[3, 4] x [1, 2] = [[3, 1], [3, 2], [4, 1], [4, 2]]
[1, 2] x []     = []
[]     x [1, 2] = []
[1, a] x [2, b] = [[1, 2], [1, b], [a, 2], [a, b]]

[1776, 1789] x [7, 12] x [4, 14, 23] x [0, 1] = 
[
    [1776, 7, 4, 0]
    [1776, 7, 4, 1]
    [1776, 7, 14, 0]
    [1776, 7, 14, 1]
    [1776, 7, 23, 0]
    [1776, 7, 23, 1]
    [1776, 12, 4, 0]
    [1776, 12, 4, 1]
    [1776, 12, 14, 0]
    [1776, 12, 14, 1]
    [1776, 12, 23, 0]
    [1776, 12, 23, 1]
    [1789, 7, 4, 0]
    [1789, 7, 4, 1]
    [1789, 7, 14, 0]
    [1789, 7, 14, 1]
    [1789, 7, 23, 0]
    [1789, 7, 23, 1]
    [1789, 12, 4, 0]
    [1789, 12, 4, 1]
    [1789, 12, 14, 0]
    [1789, 12, 14, 1]
    [1789, 12, 23, 0]
    [1789, 12, 23, 1]
]

[1, 2, 3] x [30] x [500, 100] = 
[
    [1, 30, 500]
    [1, 30, 100]
    [2, 30, 500]
    [2, 30, 100]
    [3, 30, 500]
    [3, 30, 100]
]

[1, 2, 3] x [] x [500, 100] = 
[
    
]

[1, 2, 3] x [30] x [a, b] = 
[
    [1, 30, a]
    [1, 30, b]
    [2, 30, a]
    [2, 30, b]
    [3, 30, a]
    [3, 30, b]
]

langur

val .X = fn(... .x) { .x }

writeln mapX(.X, [1, 2], [3, 4]) == [[1, 3], [1, 4], [2, 3], [2, 4]]
writeln mapX(.X, [3, 4], [1, 2]) == [[3, 1], [3, 2], [4, 1], [4, 2]]
writeln mapX(.X, [1, 2], []) == []
writeln mapX(.X, [], [1, 2]) == []
writeln()

writeln mapX .X, [1776, 1789], [7, 12], [4, 14, 23], [0, 1]
writeln()

writeln mapX .X, [1, 2, 3], [30], [500, 100]
writeln()

writeln mapX .X, [1, 2, 3], [], [500, 100]
writeln()
Output:
true
true
true
true

[[1776, 7, 4, 0], [1776, 7, 4, 1], [1776, 7, 14, 0], [1776, 7, 14, 1], [1776, 7, 23, 0], [1776, 7, 23, 1], [1776, 12, 4, 0], [1776, 12, 4, 1], [1776, 12, 14, 0], [1776, 12, 14, 1], [1776, 12, 23, 0], [1776, 12, 23, 1], [1789, 7, 4, 0], [1789, 7, 4, 1], [1789, 7, 14, 0], [1789, 7, 14, 1], [1789, 7, 23, 0], [1789, 7, 23, 1], [1789, 12, 4, 0], [1789, 12, 4, 1], [1789, 12, 14, 0], [1789, 12, 14, 1], [1789, 12, 23, 0], [1789, 12, 23, 1]]

[[1, 30, 500], [1, 30, 100], [2, 30, 500], [2, 30, 100], [3, 30, 500], [3, 30, 100]]

[]

Lua

Functional

An iterator is created to output the product items.

  local pk,upk = table.pack, table.unpack
  local getn = function(t)return #t end
  local const = function(k)return function(e) return k end end
  local function attachIdx(f)-- one-time-off function modifier
    local idx = 0
    return function(e)idx=idx+1 ; return f(e,idx)end
  end  
  
  local function reduce(t,acc,f)
    for i=1,t.n or #t do acc=f(acc,t[i])end
    return acc
  end
  local function imap(t,f)
    local r = {n=t.n or #t, r=reduce, u=upk, m=imap}
    for i=1,r.n do r[i]=f(t[i])end
    return r
  end

  local function prod(...)
    local ts = pk(...)
    local limit = imap(ts,getn)
    local idx, cnt = imap(limit,const(1)),  0
    local max = reduce(limit,1,function(a,b)return a*b end)
    local function ret(t,i)return t[idx[i]] end
    return function()
      if cnt>=max then return end -- no more output
      if cnt==0 then -- skip for 1st
        cnt = cnt + 1 
      else
        cnt, idx[#idx] = cnt + 1, idx[#idx] + 1 
        for i=#idx,2,-1 do -- update index list
          if idx[i]<=limit[i] then 
            break -- no further update need
          else -- propagate limit overflow
            idx[i],idx[i-1] = 1, idx[i-1]+1
          end        
        end        
      end
      return cnt,imap(ts,attachIdx(ret)):u()
    end    
  end
--- test
  for i,a,b in prod({1,2},{3,4}) do
    print(i,a,b)
  end
  print()
  for i,a,b in prod({3,4},{1,2}) do
    print(i,a,b)
  end
Output:
1	1	3
2	1	4
3	2	3
4	2	4

1	3	1
2	3	2
3	4	1
4	4	2

Using coroutines

I have not benchmarked this, but I believe that this should run faster than the functional implementation and also likely the imperative implementation, it has significantly fewer function calls per iteration, and only the stack changes during iteration (no garbage collection during iteration). On the other hand due to avoiding garbage collection, result is reused between returns, so mutating the returned result is unsafe.

It is possible that specialising descend by depth may yield a further improvement in performance, but it would only be able to eliminate the lookup of sets[depth] and the if test, because the reference to result[depth] is required; I doubt the increase in complexity would be worth the (potential) improvement in performance.

local function cartesian_product(sets)
  local result = {}
  local set_count = #sets
--[[ I believe that this should make the below go very slightly faster, because it doesn't need to lookup yield in coroutine each time it
     yields, though perhaps the compiler optimises the lookup away? ]]
  local yield = coroutine.yield 
  local function descend(depth)
    if depth == set_count then
      for k,v in pairs(sets[depth]) do
        result[depth] = v
        yield(result)
      end
    else
      for k,v in pairs(sets[depth]) do
        result[depth] = v
        descend(depth + 1)
      end
    end
  end
  return coroutine.wrap(function() descend(1) end)
end

--- tests
local test_cases = {
  {{1, 2}, {3, 4}},
  {{3, 4}, {1, 2}},
  {{1776, 1789}, {7, 12}, {4, 14, 23}, {0,1}},
  {{1,2,3}, {30}, {500, 100}},
  {{1,2,3}, {}, {500, 100}}
}

local function format_nested_list(list)
  if list[1] and type(list[1]) == "table" then
    local formatted_items = {}
    for i, item in ipairs(list) do
      formatted_items[i] = format_nested_list(item)
    end
    return format_nested_list(formatted_items)
  else
    return "{" .. table.concat(list, ",") .. "}"
  end
end

for _,test_case in ipairs(test_cases) do
  print(format_nested_list(test_case))
  for product in cartesian_product(test_case) do
    print("  " .. format_nested_list(product))
  end
end

Imperative iterator

The functional implementation restated as an imperative iterator, also adjusted to not allocate a new result table on each iteration; this saves time, but makes mutating the returned table unsafe.

local function cartesian_product(sets)
  local item_counts = {}
  local indices = {}
  local results = {}
  local set_count = #sets
  local combination_count = 1
  
  for set_index=set_count, 1, -1 do
    local set = sets[set_index]
    local item_count = #set
    item_counts[set_index] = item_count
    indices[set_index] = 1
    results[set_index] = set[1]
    combination_count = combination_count * item_count
  end
  
  local combination_index = 0
  
  return function()
    if combination_index >= combination_count then return end -- no more output

    if combination_index == 0 then goto skip_update end -- skip first index update
    
    indices[set_count] = indices[set_count] + 1
    
    for set_index=set_count, 1, -1 do -- update index list
      local set = sets[set_index]
      local index = indices[set_index]
      if index <= item_counts[set_index] then
        results[set_index] = set[index]
        break -- no further update needed
      else -- propagate item_counts overflow
        results[set_index] = set[1]
        indices[set_index] = 1
        if set_index > 1 then
          indices[set_index - 1] = indices[set_index - 1] + 1
        end
      end
    end
    
    ::skip_update::
    
    combination_index = combination_index + 1
    
    return combination_index, results
  end
end
--- tests
local test_cases = {
  {{1, 2}, {3, 4}},
  {{3, 4}, {1, 2}},
  {{1776, 1789}, {7, 12}, {4, 14, 23}, {0,1}},
  {{1,2,3}, {30}, {500, 100}},
  {{1,2,3}, {}, {500, 100}}
}

local function format_nested_list(list)
  if list[1] and type(list[1]) == "table" then
    local formatted_items = {}
    for i, item in ipairs(list) do
      formatted_items[i] = format_nested_list(item)
    end
    return format_nested_list(formatted_items)
  else
    return "{" .. table.concat(list, ",") .. "}"
  end
end

for _,test_case in ipairs(test_cases) do
  print(format_nested_list(test_case))
  for i, product in cartesian_product(test_case) do
    print(i, format_nested_list(product))
  end
end

Functional-esque (non-iterator)

Motivation: If a list-of-lists is passed into the cartesian product, then wouldn't a list-of-lists be the expected return type? Of course this is just personal opinion/preference, other implementations are fine as-is if you'd rather have an iterator.

-- support:
function T(t) return setmetatable(t, {__index=table}) end
table.clone = function(t) local s=T{} for k,v in ipairs(t) do s[k]=v end return s end
table.reduce = function(t,f,acc) for i=1,#t do acc=f(t[i],acc) end return acc end

-- implementation:
local function cartprod(sets)
  local temp, prod = T{}, T{}
  local function descend(depth)
    for _,v in ipairs(sets[depth]) do
      temp[depth] = v
      if (depth==#sets) then prod[#prod+1]=temp:clone() else descend(depth+1) end
    end
  end
  descend(1)
  return prod
end

-- demonstration:
tests = {
  { {1, 2}, {3, 4} },
  { {3, 4}, {1, 2} },
  { {1, 2}, {} },
  { {}, {1, 2} },
  { {1776, 1789}, {7, 12}, {4, 14, 23}, {0, 1} },
  { {1, 2, 3}, {30}, {500, 100} },
  { {1, 2, 3}, {}, {500, 100} }
}
for _,test in ipairs(tests) do
  local cp = cartprod(test)
  print("{"..cp:reduce(function(t,a) return (a=="" and a or a..", ").."("..t:concat(", ")..")" end,"").."}")
end
Output:
{(1, 3), (1, 4), (2, 3), (2, 4)}
{(3, 1), (3, 2), (4, 1), (4, 2)}
{}
{}
{(1776, 7, 4, 0), (1776, 7, 4, 1), (1776, 7, 14, 0), (1776, 7, 14, 1), (1776, 7, 23, 0), (1776, 7, 23, 1), (1776, 12, 4, 0), (1776, 12, 4, 1), (1776, 12, 14, 0), (1776, 12, 14, 1), (1776, 12, 23, 0), (1776, 12, 23, 1), (1789, 7, 4, 0), (1789, 7, 4, 1), (1789, 7, 14, 0), (1789, 7, 14, 1), (1789, 7, 23, 0), (1789, 7, 23, 1), (1789, 12, 4, 0), (1789, 12, 4, 1), (1789, 12, 14, 0), (1789, 12, 14, 1), (1789, 12, 23, 0), (1789, 12, 23, 1)}
{(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)}
{}

Maple

cartmulti := proc ()
 local m, v;
 if [] in {args} then
 return [];
 else 
m := Iterator:-CartesianProduct(args);
 for v in m do
 printf("%{}a\n", v);
 end do;
 end if;
 end proc;

Mathematica/Wolfram Language

cartesianProduct[args__] := Flatten[Outer[List, args], Length[{args}] - 1]

Maxima

Using built-in function cartesian_product

cartesian_product({1,2},{3,4});
/* {[1,3],[1,4],[2,3],[2,4]} */
cartesian_product({3,4},{1,2});
/* {[3,1],[3,2],[4,1],[4,2]} */
cartesian_product({1,2},{});
/* {} */
cartesian_product({},{1,2});
/* {} */

Using built-in function cartesian_product_list

cartesian_product_list([1,2],[3,4]);
/* [[1,3],[1,4],[2,3],[2,4]] */
cartesian_product_list([3,4],[1,2]);
/* [[3,1],[3,2],[4,1],[4,2]] */
cartesian_product_list([1,2],[]);
/* [] */
cartesian_product_list([],[1,2]);
/* [] */

Using built-in function create_list

create_list([i,j],i,[1,2],j,[3,4]);
/* [[1,3],[1,4],[2,3],[2,4]] */
create_list([i,j],i,[3,4],j,[1,2]);
/* [[3,1],[3,2],[4,1],[4,2]] */
create_list([i,j],i,[1,2],j,[]);
/* [] */
create_list([i,j],i,[],j,[1,2]);
/* [] */

Extra credit

my_cartesian(lst1,lst2):=create_list([i,j],i,lst1,j,lst2);
n_ary_cartesian(singleargument):=block(lreduce(my_cartesian,singleargument),map(flatten,%%));

[[1776,1789],[7,12],[4,14,23],[0,1]]$
n_ary_cartesian(%);
/* 	[[1776,7,4,0],[1776,7,4,1],[1776,7,14,0],[1776,7,14,1],[1776,7,23,0],[1776,7,23,1],[1776,12,4,0],[1776,12,4,1],[1776,12,14,0],[1776,12,14,1],[1776,12,23,0],[1776,12,23,1],[1789,7,4,0],[1789,7,4,1],[1789,7,14,0],[1789,7,14,1],[1789,7,23,0],[1789,7,23,1],[1789,12,4,0],[1789,12,4,1],[1789,12,14,0],[1789,12,14,1],[1789,12,23,0],[1789,12,23,1]] */

[[1,2,3],[30],[500,100]]$
n_ary_cartesian(%);
/* [[1,30,500],[1,30,100],[2,30,500],[2,30,100],[3,30,500],[3,30,100]] */

[[1,2,3],[],[500,100]]$
n_ary_cartesian(%);
/* [] */

Modula-2

MODULE CartesianProduct;
FROM FormatString IMPORT FormatString;
FROM Terminal IMPORT WriteString,WriteLn,ReadChar;

PROCEDURE WriteInt(a : INTEGER);
VAR buf : ARRAY[0..9] OF CHAR;
BEGIN
    FormatString("%i", buf, a);
    WriteString(buf)
END WriteInt;

PROCEDURE Cartesian(a,b : ARRAY OF INTEGER);
VAR i,j : CARDINAL;
BEGIN
    WriteString("[");
    FOR i:=0 TO HIGH(a) DO
        FOR j:=0 TO HIGH(b) DO
            IF (i>0) OR (j>0) THEN
                WriteString(",");
            END;
            WriteString("[");
            WriteInt(a[i]);
            WriteString(",");
            WriteInt(b[j]);
            WriteString("]")
        END
    END;
    WriteString("]");
    WriteLn
END Cartesian;

TYPE
    AP = ARRAY[0..1] OF INTEGER;
    E = ARRAY[0..0] OF INTEGER;
VAR
    a,b : AP;
BEGIN
    a := AP{1,2};
    b := AP{3,4};
    Cartesian(a,b);

    a := AP{3,4};
    b := AP{1,2};
    Cartesian(a,b);

    (* If there is a way to create an empty array, I do not know of it *)

    ReadChar
END CartesianProduct.

Nim

Task: product of two lists

To compute the product of two lists (Nim arrays or sequences), we use an iterator. Obtaining a sequence from an iterator is easily done using "toSeq" from the module “sequtils” of the standard library.

The procedure allows to mix sequences of different types, for instance integers and characters.

In order to display the result using mathematical formalism, we have created a special procedure “$$” for the sequences and have overloaded the procedure “$” for tuples.

iterator product[T1, T2](a: openArray[T1]; b: openArray[T2]): tuple[a: T1, b: T2] =
  # Yield the element of the cartesian product of "a" and "b".
  # Yield tuples rather than arrays as it allows T1 and T2 to be different.
  
  for x in a:
    for y in b:
      yield (x, y)

#———————————————————————————————————————————————————————————————————————————————————————————————————

when isMainModule:

  from seqUtils import toSeq
  import strformat
  from strutils import addSep

  #-------------------------------------------------------------------------------------------------

  proc `$`[T1, T2](t: tuple[a: T1, b: T2]): string =
    ## Overloading of `$` to display a tuple without the field names.
    &"({t.a}, {t.b})"

  proc `$$`[T](s: seq[T]): string =
    ## New operator to display a sequence using mathematical set notation.
    result = "{"
    for item in s:
      result.addSep(", ", 1)
      result.add($item)
    result.add('}')

#-------------------------------------------------------------------------------------------------

  const Empty = newSeq[int]()   # Empty list of "int".

  for (a, b) in [(@[1, 2], @[3, 4]),
                 (@[3, 4], @[1, 2]),
                 (@[1, 2],  Empty ),
                 ( Empty,  @[1, 2])]:

    echo &"{$$a} x {$$b} = {$$toSeq(product(a, b))}"
Output:
1, 2} x {3, 4} = {(1, 3), (1, 4), (2, 3), (2, 4)}
{3, 4} x {1, 2} = {(3, 1), (3, 2), (4, 1), (4, 2)}
{1, 2} x {} = {}
{} x {1, 2} = {}

Extra credit: product of n list

Recursive procedure

As iterators cannot be recursive, we have to use a procedure which returns the whole sequence. And as we don’t know the number of sequences, we use a “varargs”. So all the sequences must contain the same type of values, values which are returned as sequences and not tuples.

Note that there exists in the standard module “algorithm” a procedure which computes the product of sequences of a same type. It is not recursive and, so, likely more efficient that the following version.

proc product[T](a: varargs[seq[T]]): seq[seq[T]] =
  ## Return the product of several sets (sequences).

  if a.len == 1:
    for x in a[0]:
      result.add(@[x])
  else:
    for x in a[0]:
      for s in product(a[1..^1]):
        result.add(x & s)

#———————————————————————————————————————————————————————————————————————————————————————————————————

when isMainModule:

  import strformat
  
  let
    a = @[1, 2]
    b = @[3, 4]
    c = @[5, 6]
  echo &"{a} x {b} x {c} = {product(a, b, c)}"
Output:
@[1, 2] x @[3, 4] x @[5, 6] = @[@[1, 3, 5], @[1, 3, 6], @[1, 4, 5], @[1, 4, 6], @[2, 3, 5], @[2, 3, 6], @[2, 4, 5], @[2, 4, 6]]

Using a macro

Another way to compute the product consists to use a macro. It would be possible to create an iterator but it’s somewhat easier to produce the code to build the whole sequence. No recursion here: we generate nested loops, so the algorithm is the simplest possible.

With a macro, we are able to mix several value types: the “varrags” is no longer a problem as being used at compile time it may contain sequences of different types. And we are able to return tuples of n values instead of sequences of n values.

import macros

macro product(args: varargs[typed]): untyped =
  ## Macro to generate the code to build the product of several sequences.

  let t = args[0].getType()
  if t.kind != nnkBracketExpr or t[0].kind != nnkSym or $t[0] != "seq":
    error("Arguments must be sequences", args)

  # Build the result type i.e. a tuple with "args.len" elements.
  # Fields are named "f0", "f1", etc.
  let tupleTyNode = newNimNode(nnkTupleTy)
  for idx, arg in args:
    let identDefsNode = newIdentDefs(ident('f' & $idx), arg.getType()[1])
    tupleTyNode.add(identDefsNode)

  # Build the nested for loops with counter "i0", "i1", etc.
  var stmtListNode = newStmtList()
  let loopsNode = nnkForStmt.newTree(ident("i0"), ident($args[0]), stmtListNode)
  var idx = 0
  for arg in args[1..^1]:
    inc idx
    let loopNode = nnkForStmt.newTree(ident('i' & $idx), ident($arg))
    stmtListNode.add(loopNode)
    stmtListNode = newStmtList()
    loopNode.add(stmtListNode)

  # Build the instruction "result.add(i1, i2,...)".
  let parNode = newPar()
  let addNode = newCall(newDotExpr(ident("result"), ident("add")), parNode)
  for i, arg in args:
    parNode.add(ident('i' & $i))
  stmtListNode.add(addNode)

  # Build the tree.
  result = nnkStmtListExpr.newTree(
             nnkVarSection.newTree(
               newIdentDefs(
                 ident("result"),
                 nnkBracketExpr.newTree(ident("seq"), tupleTyNode))),
               loopsNode,
             ident("result"))

#———————————————————————————————————————————————————————————————————————————————————————————————————

when isMainModule:

  import strformat
  import strutils

  #-------------------------------------------------------------------------------------------------

  proc `$`[T: tuple](t: T): string =
    ## Overloading of `$` to display a tuple without the field names.
    result = "("
    for f in t.fields:
      result.addSep(", ", 1)
      result.add($f)
    result.add(']')

  proc `$$`[T](s: seq[T]): string =
    ## New operator to display a sequence using mathematical set notation.
    result = "{"
    for item in s:
      result.addSep(", ", 1)
      result.add($item)
    result.add('}')

  #-------------------------------------------------------------------------------------------------

  var a = @[1, 2]
  var b = @['a', 'b']
  var c = @[false, true]
  echo &"{$$a} x {$$b} x {$$c} = {$$product(a, b, c)}"
Output:
{1, 2} x {a, b} x {false, true} = {(1, a, false], (1, a, true], (1, b, false], (1, b, true], (2, a, false], (2, a, true], (2, b, false], (2, b, true]}

OCaml

The double semicolons are necessary only for the toplevel

Naive but more readable version

let rec product l1 l2 = 
    match l1, l2 with
    | [], _ | _, [] -> []
    | h1::t1, h2::t2 -> (h1,h2)::(product [h1] t2)@(product t1 l2)
;;

product [1;2] [3;4];;
(*- : (int * int) list = [(1, 3); (1, 4); (2, 3); (2, 4)]*)
product [3;4] [1;2];;
(*- : (int * int) list = [(3, 1); (3, 2); (4, 1); (4, 2)]*)
product [1;2] [];;
(*- : (int * 'a) list = []*)
product [] [1;2];;
(*- : ('a * int) list = []*)

Implementation with a bit more tail-call optimization, introducing a helper function. The order of the result is changed but it should not be an issue for most uses.

let product' l1 l2 = 
    let rec aux ~acc l1' l2' = 
        match l1', l2' with
        | [], _ | _, [] -> acc
        | h1::t1, h2::t2 -> 
            let acc = (h1,h2)::acc in
            let acc = aux ~acc t1 l2' in
            aux ~acc [h1] t2
    in aux [] l1 l2
;;

product' [1;2] [3;4];;
(*- : (int * int) list = [(1, 4); (2, 4); (2, 3); (1, 3)]*)
product' [3;4] [1;2];;
(*- : (int * int) list = [(3, 2); (4, 2); (4, 1); (3, 1)]*)
product' [1;2] [];;
(*- : (int * 'a) list = []*)
product' [] [1;2];;
(*- : ('a * int) list = []*)

Implemented using nested folds:

let cart_prod l1 l2 =
  List.fold_left (fun acc1 ele1 ->
    List.fold_left (fun acc2 ele2 -> (ele1,ele2)::acc2) acc1 l2) [] l1 ;;

cart_prod [1; 2; 3] ['a'; 'b'; 'c'] ;;
(*- : (int * char) list = [(3, 'c'); (3, 'b'); (3, 'a'); (2, 'c'); (2, 'b'); (2, 'a'); (1, 'c'); (1, 'b'); (1, 'a')]*)
cart_prod [1; 2; 3] [] ;;
(*- : ('a * int) list = [] *)

Extra credit function. Since in OCaml a function can return only one type, and because tuples of different arities are different types, this returns a list of lists rather than a list of tuples. Since lists are homogeneous this version is restricted to products over a single type, eg integers.

let rec product'' l = 
    (* We need to do the cross product of our current list and all the others
     * so we define a helper function for that *)
    let rec aux ~acc l1 l2 = match l1, l2 with
    | [], _ | _, [] -> acc
    | h1::t1, h2::t2 -> 
        let acc = (h1::h2)::acc in
        let acc = (aux ~acc t1 l2) in
        aux ~acc [h1] t2
    (* now we can do the actual computation *)
    in match l with
    | [] -> []
    | [l1] -> List.map (fun x -> [x]) l1
    | l1::tl ->
        let tail_product = product'' tl in
        aux ~acc:[] l1 tail_product


product'' [[1;2];[3;4]];;
(*- : int list list = [[1; 4]; [2; 4]; [2; 3]; [1; 3]]*)
product'' [[3;4];[1;2]];;
(*- : int list list = [[3; 2]; [4; 2]; [4; 1]; [3; 1]]*)
product'' [[1;2];[]];;
(*- : int list list = []*)
product'' [[];[1;2]];;
(*- : int list list = []*)
product'' [[1776; 1789];[7; 12];[4; 14; 23];[0; 1]];;
(*
- : int list list =

[[1776; 7; 4; 1]; [1776; 12; 4; 1]; [1776; 12; 14; 1]; [1776; 12; 23; 1];
 [1776; 12; 23; 0]; [1776; 12; 14; 0]; [1776; 12; 4; 0]; [1776; 7; 14; 1];
 [1776; 7; 23; 1]; [1776; 7; 23; 0]; [1776; 7; 14; 0]; [1789; 7; 4; 1];
 [1789; 12; 4; 1]; [1789; 12; 14; 1]; [1789; 12; 23; 1]; [1789; 12; 23; 0];
 [1789; 12; 14; 0]; [1789; 12; 4; 0]; [1789; 7; 14; 1]; [1789; 7; 23; 1];
 [1789; 7; 23; 0]; [1789; 7; 14; 0]; [1789; 7; 4; 0]; [1776; 7; 4; 0]]
*)
product'' [[1; 2; 3];[30];[500; 100]];;
(*
- : int list list =

[[1; 30; 500]; [2; 30; 500]; [3; 30; 500]; [3; 30; 100]; [2; 30; 100];
 [1; 30; 100]]
*)
product'' [[1; 2; 3];[];[500; 100]];;
(*- : int list list = []*)

Better type

In the latter example, our function has this signature:

val product'' : 'a list list -> 'a list list = <fun>

This lacks clarity as those two lists are not equivalent since one replaces a tuple. We can get a better signature by creating a tuple type:

type 'a tuple = 'a list

let rec product'' (l:'a list tuple) =
    (* We need to do the cross product of our current list and all the others
     * so we define a helper function for that *)
    let rec aux ~acc l1 l2 = match l1, l2 with
    | [], _ | _, [] -> acc
    | h1::t1, h2::t2 ->
        let acc = (h1::h2)::acc in
        let acc = (aux ~acc t1 l2) in
        aux ~acc [h1] t2
    (* now we can do the actual computation *)
    in match l with
    | [] -> []
    | [l1] -> List.map ~f:(fun x -> ([x]:'a tuple)) l1
    | l1::tl ->
        let tail_product = product'' tl in
        aux ~acc:[] l1 tail_product
;;

type 'a tuple = 'a list
val product'' : 'a list tuple -> 'a tuple list = <fun>

Perl

Iterative

Nested loops, with a short-circuit to quit early if any term is an empty set.

sub cartesian {
    my $sets = shift @_;
    for (@$sets) { return [] unless @$_ }

    my $products = [[]];
    for my $set (reverse @$sets) {
        my $partial = $products;
        $products = [];
        for my $item (@$set) {
            for my $product (@$partial) {
                push @$products, [$item, @$product];
            }
        }
    }
    $products;
}

sub product {
    my($s,$fmt) = @_;
    my $tuples;
    for $a ( @{ cartesian( \@$s ) } ) { $tuples .= sprintf "($fmt) ", @$a; }
    $tuples . "\n";
}

print 
product([[1, 2],      [3, 4]                  ], '%1d %1d'        ).
product([[3, 4],      [1, 2]                  ], '%1d %1d'        ).
product([[1, 2],      []                      ], '%1d %1d'        ).
product([[],          [1, 2]                  ], '%1d %1d'        ).
product([[1,2,3],     [30],   [500,100]       ], '%1d %1d %3d'    ).
product([[1,2,3],     [],     [500,100]       ], '%1d %1d %3d'    ).
product([[1776,1789], [7,12], [4,14,23], [0,1]], '%4d %2d %2d %1d')
Output:
(1 3) (1 4) (2 3) (2 4)
(3 1) (3 2) (4 1) (4 2)


(1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100)

(1776  7  4 0) (1776  7  4 1) (1776  7 14 0) (1776  7 14 1) (1776  7 23 0) (1776  7 23 1) (1776 12  4 0) (1776 12  4 1) (1776 12 14 0) (1776 12 14 1) (1776 12 23 0) (1776 12 23 1) (1789  7  4 0) (1789  7  4 1) (1789  7 14 0) (1789  7 14 1) (1789  7 23 0) (1789  7 23 1) (1789 12  4 0) (1789 12  4 1) (1789 12 14 0) (1789 12 14 1) (1789 12 23 0) (1789 12 23 1)

Glob

This being Perl, there's more than one way to do it. A quick demonstration of how glob, more typically used for filename wildcard expansion, can solve the task.

$tuples = [ map { [split /:/] } glob '{1,2,3}:{30}:{500,100}' ];

for $a (@$tuples) { printf "(%1d %2d %3d) ", @$a; }
Output:
(1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100)

Modules

A variety of modules can do this correctly for an arbitrary number of lists (each of independent length). Arguably using modules is very idiomatic Perl.

use ntheory qw/forsetproduct/;
forsetproduct { say "@_" } [1,2,3],[qw/a b c/],[qw/@ $ !/];

use Set::Product qw/product/;
product { say "@_" } [1,2,3],[qw/a b c/],[qw/@ $ !/];

use Math::Cartesian::Product;
cartesian { say "@_" } [1,2,3],[qw/a b c/],[qw/@ $ !/];

use Algorithm::Loops qw/NestedLoops/;
NestedLoops([[1,2,3],[qw/a b c/],[qw/@ $ !/]], sub { say "@_"; });

Phix

with javascript_semantics
function cart(sequence s)
    sequence res = {}
    for n=2 to length(s) do
        for i=1 to length(s[1]) do
            for j=1 to length(s[2]) do
                res = append(res,s[1][i]&s[2][j])
            end for
        end for
        if length(s)=2 then exit end if
        s[1..2] = {res}
        res = {}
    end for
    return res
end function
 
?cart({{1,2},{3,4}})
?cart({{3,4},{1,2}})
?cart({{1,2},{}})
?cart({{},{1,2}})
?cart({{1776, 1789},{7, 12},{4, 14, 23},{0, 1}})
?cart({{1, 2, 3},{30},{500, 100}})
?cart({{1, 2, 3},{},{500, 100}})
Output:
{{1,3},{1,4},{2,3},{2,4}}
{{3,1},{3,2},{4,1},{4,2}}
{}
{}
{{1776,7,4,0},{1776,7,4,1},{1776,7,14,0},{1776,7,14,1},{1776,7,23,0},{1776,7,23,1},
 {1776,12,4,0},{1776,12,4,1},{1776,12,14,0},{1776,12,14,1},{1776,12,23,0},{1776,12,23,1},
 {1789,7,4,0},{1789,7,4,1},{1789,7,14,0},{1789,7,14,1},{1789,7,23,0},{1789,7,23,1},
 {1789,12,4,0},{1789,12,4,1},{1789,12,14,0},{1789,12,14,1},{1789,12,23,0},{1789,12,23,1}}
{{1,30,500},{1,30,100},{2,30,500},{2,30,100},{3,30,500},{3,30,100}}
{}

Phixmonti

include ..\Utilitys.pmt

def cart
    ( ) var res
    -1 get var ta -1 del
    -1 get var he -1 del
    ta "" != he "" != and if
        he len nip for
            he swap get var h drop
            ta len nip for
                ta swap get var t drop
                ( h t ) flatten res swap 0 put var res
            endfor
        endfor
        len if res 0 put cart endif
    endif
enddef

/# ---------- MAIN ---------- #/

( ( 1 2 ) ( 3 4 ) ) cart
drop res print nl nl

( ( 1776 1789 ) ( 7 12 ) ( 4 14 23 ) ( 0 1 ) ) cart
drop res print nl nl

( ( 1 2 3 ) ( 30 ) ( 500 100 ) ) cart
drop res print nl nl

( ( 1 2 ) ( ) ) cart
drop res print nl nl

PicoLisp

(de 2lists (L1 L2)
   (mapcan
      '((I)
         (mapcar
            '((A) ((if (atom A) list cons) I A))
            L2 ) )
      L1 ) )
(de reduce (L . @)
   (ifn (rest) L (2lists L (apply reduce (rest)))) )
(de cartesian (L . @)
   (and L (rest) (pass reduce L)) )

(println
   (cartesian (1 2)) )
(println
   (cartesian NIL (1 2)) )
(println
   (cartesian (1 2) (3 4)) )
(println
   (cartesian (3 4) (1 2)) )
(println
   (cartesian (1776 1789) (7 12) (4 14 23) (0 1)) )
(println
   (cartesian (1 2 3) (30) (500 100)) )
(println
   (cartesian (1 2 3) NIL (500 100)) )
Output:
NIL
NIL
((1 3) (1 4) (2 3) (2 4))
((3 1) (3 2) (4 1) (4 2))
((1776 7 4 0) (1776 7 4 1) (1776 7 14 0) (1776 7 14 1) (1776 7 23 0) (1776 7 23 1) (1776 12 4 0) (1776 12 4 1) (1776 12 14 0) (1776 12 14 1) (1776 12 23 0) (1776 12 23 1) (1789 7 4 0) (1789 7 4 1) (1789 7 14 0) (1789 7 14 1) (1789 7 23 0) (1789 7 23 1) (1789 12 4 0) (1789 12 4 1) (1789 12 14 0) (1789 12 14 1) (1789 12 23 0) (1789 12 23 1))
((1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100))
NIL

Prolog

product([A|_], Bs, [A, B]) :- member(B, Bs).
product([_|As], Bs, X) :- product(As, Bs, X).
Output:
?- findall(X, product([1,2],[3,4],X), S).
S = [[1, 3], [1, 4], [2, 3], [2, 4]].

?- findall(X, product([3,4],[1,2],X), S).
S = [[3, 1], [3, 2], [4, 1], [4, 2]].

?- findall(X, product([1,2,3],[],X), S).
S = [].

?- findall(X, product([],[1,2,3],X), S).
S = [].

Python

Using itertools

import itertools

def cp(lsts):
    return list(itertools.product(*lsts))

if __name__ == '__main__':
    from pprint import pprint as pp
    
    for lists in [[[1,2],[3,4]], [[3,4],[1,2]], [[], [1, 2]], [[1, 2], []],
                  ((1776, 1789),  (7, 12), (4, 14, 23), (0, 1)),
                  ((1, 2, 3), (30,), (500, 100)),
                  ((1, 2, 3), (), (500, 100))]:
        print(lists, '=>')
        pp(cp(lists), indent=2)
Output:
[[1, 2], [3, 4]] =>
[(1, 3), (1, 4), (2, 3), (2, 4)]
[[3, 4], [1, 2]] =>
[(3, 1), (3, 2), (4, 1), (4, 2)]
[[], [1, 2]] =>
[]
[[1, 2], []] =>
[]
((1776, 1789), (7, 12), (4, 14, 23), (0, 1)) =>
[ (1776, 7, 4, 0),
  (1776, 7, 4, 1),
  (1776, 7, 14, 0),
  (1776, 7, 14, 1),
  (1776, 7, 23, 0),
  (1776, 7, 23, 1),
  (1776, 12, 4, 0),
  (1776, 12, 4, 1),
  (1776, 12, 14, 0),
  (1776, 12, 14, 1),
  (1776, 12, 23, 0),
  (1776, 12, 23, 1),
  (1789, 7, 4, 0),
  (1789, 7, 4, 1),
  (1789, 7, 14, 0),
  (1789, 7, 14, 1),
  (1789, 7, 23, 0),
  (1789, 7, 23, 1),
  (1789, 12, 4, 0),
  (1789, 12, 4, 1),
  (1789, 12, 14, 0),
  (1789, 12, 14, 1),
  (1789, 12, 23, 0),
  (1789, 12, 23, 1)]
((1, 2, 3), (30,), (500, 100)) =>
[ (1, 30, 500),
  (1, 30, 100),
  (2, 30, 500),
  (2, 30, 100),
  (3, 30, 500),
  (3, 30, 100)]
((1, 2, 3), (), (500, 100)) =>
[]

Using the 'Applicative' abstraction

This task calls for alternative approaches to defining cartesian products, and one particularly compact alternative route to a native cartesian product (in a more mathematically reasoned idiom of programming) is through the Applicative abstraction (see Applicative Functor), which is slightly more general than the possibly better known monad structure. Applicative functions are provided off-the-shelf by languages like Agda, Idris, Haskell and Scala, and can usefully be implemented in any language, including Python, which supports higher-order functions.

If we write ourselves a re-usable Python ap function for the case of lists (applicative functions for other 'data containers' can also be written – this one applies a list of functions to a list of values):

# ap (<*>) :: [(a -> b)] -> [a] -> [b]
def ap(fs):
    return lambda xs: foldl(
        lambda a: lambda f: a + foldl(
            lambda a: lambda x: a + [f(x)])([])(xs)
    )([])(fs)

then one simple use of it will be to define the cartesian product of two lists (of possibly different type) as:

ap(map(Tuple, xs))

where Tuple is a constructor, and xs is bound to the first of two lists. The returned value is a function which can be applied to a second list.

For an nAry product, we can then use a fold (catamorphism) to lift the basic function over two lists cartesianProduct :: [a] -> [b] -> [(a, b)] to a function over a list of lists:

# nAryCartProd :: [[a], [b], [c] ...] -> [(a, b, c ...)]
def nAryCartProd(xxs):
    return foldl1(cartesianProduct)(
        xxs
    )

For example:

# Two lists -> list of tuples


# cartesianProduct :: [a] -> [b] -> [(a, b)]
def cartesianProduct(xs):
    return ap(map(Tuple, xs))


# List of lists -> list of tuples

# nAryCartProd :: [[a], [b], [c] ...] -> [(a, b, c ...)]
def nAryCartProd(xxs):
    return foldl1(cartesianProduct)(
        xxs
    )


# main :: IO ()
def main():
    # Product of lists of different types
    print (
        'Product of two lists of different types:'
    )
    print(
        cartesianProduct(['a', 'b', 'c'])(
            [1, 2]
        )
    )

    # TESTS OF PRODUCTS OF TWO LISTS

    print(
        '\nSpecified tests of products of two lists:'
    )
    print(
        cartesianProduct([1, 2])([3, 4]),
        ' <--> ',
        cartesianProduct([3, 4])([1, 2])
    )
    print (
        cartesianProduct([1, 2])([]),
        ' <--> ',
        cartesianProduct([])([1, 2])
    )

    # TESTS OF N-ARY CARTESIAN PRODUCTS

    print('\nSpecified tests of nAry products:')
    for xs in nAryCartProd([[1776, 1789], [7, 12], [4, 14, 23], [0, 1]]):
        print(xs)

    for xs in (
        map_(nAryCartProd)(
            [
                [[1, 2, 3], [30], [500, 100]],
                [[1, 2, 3], [], [500, 100]]
            ]
        )
    ):
        print(
            xs
        )

# GENERIC -------------------------------------------------


# Applicative function for lists

# ap (<*>) :: [(a -> b)] -> [a] -> [b]
def ap(fs):
    return lambda xs: foldl(
        lambda a: lambda f: a + foldl(
            lambda a: lambda x: a + [f(x)])([])(xs)
    )([])(fs)


# foldl :: (a -> b -> a) -> a -> [b] -> a
def foldl(f):
    def go(v, xs):
        a = v
        for x in xs:
            a = f(a)(x)
        return a
    return lambda acc: lambda xs: go(acc, xs)


# foldl1 :: (a -> a -> a) -> [a] -> a
def foldl1(f):
    return lambda xs: foldl(f)(xs[0])(
        xs[1:]
    ) if xs else None


# map :: (a -> b) -> [a] -> [b]
def map_(f):
    return lambda xs: list(map(f, xs))


# Tuple :: a -> b -> (a, b)
def Tuple(x):
    return lambda y: (
        x + (y,)
    ) if tuple is type(x) else (x, y)


# TEST ----------------------------------------------------
if __name__ == '__main__':
    main()
Output:
Product of two lists of different types:
[('a', 1), ('a', 2), ('b', 1), ('b', 2), ('c', 1), ('c', 2)]

Specified tests of products of two lists:
[(1, 3), (1, 4), (2, 3), (2, 4)]  <-->  [(3, 1), (3, 2), (4, 1), (4, 2)]
[]  <-->  []

Specified tests of nAry products:
(1776, 7, 4, 0)
(1776, 7, 4, 1)
(1776, 7, 14, 0)
(1776, 7, 14, 1)
(1776, 7, 23, 0)
(1776, 7, 23, 1)
(1776, 12, 4, 0)
(1776, 12, 4, 1)
(1776, 12, 14, 0)
(1776, 12, 14, 1)
(1776, 12, 23, 0)
(1776, 12, 23, 1)
(1789, 7, 4, 0)
(1789, 7, 4, 1)
(1789, 7, 14, 0)
(1789, 7, 14, 1)
(1789, 7, 23, 0)
(1789, 7, 23, 1)
(1789, 12, 4, 0)
(1789, 12, 4, 1)
(1789, 12, 14, 0)
(1789, 12, 14, 1)
(1789, 12, 23, 0)
(1789, 12, 23, 1)
[(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)]
[]

Quackery

  [ [] unrot
    swap witheach
      [ over witheach
          [ over nested 
            swap nested join 
            nested dip rot join 
            unrot ]
      drop ] drop ]             is cartprod ( [ [ --> [ )

  ' [ 1 2 ] ' [ 3 4 ] cartprod echo cr
  ' [ 3 4 ] ' [ 1 2 ] cartprod echo cr
  ' [ 1 2 ] ' [     ] cartprod echo cr
  ' [     ] ' [ 1 2 ] cartprod echo cr
Output:
[ [ 1 3 ] [ 1 4 ] [ 2 3 ] [ 2 4 ] ]
[ [ 3 1 ] [ 3 2 ] [ 4 1 ] [ 4 2 ] ]
[ ]
[ ]

R

one_w_many <- function(one, many) lapply(many, function(x) c(one,x))

# Let's define an infix operator to perform a cartesian product.

"%p%" <- function( a, b ) {
  p = c( sapply(a, function (x) one_w_many(x, b) ) )
  if (is.null(unlist(p))) list() else p}

display_prod <-
  function (xs) { for (x in xs) cat( paste(x, collapse=", "), "\n" ) }

fmt_vec <- function(v) sprintf("(%s)", paste(v, collapse=', '))

go <- function (...) {
  cat("\n", paste( sapply(list(...),fmt_vec), collapse=" * "), "\n")
  prod = Reduce( '%p%', list(...) )
  display_prod( prod ) }

Simple tests:

> display_prod(  c(1, 2) %p% c(3, 4)  )
1, 3
1, 4
2, 3
2, 4
> display_prod(  c(3, 4) %p% c(1, 2)  )
3, 1
3, 2
4, 1
4, 2
> display_prod(  c(3, 4) %p% c()  )
>

Tougher tests:

go( c(1776, 1789), c(7, 12), c(4, 14, 23), c(0, 1) )
go( c(1, 2, 3), c(30), c(500, 100) )
go( c(1, 2, 3), c(), c(500, 100) )
Output:
 (1776, 1789) * (7, 12) * (4, 14, 23) * (0, 1)
1776, 7, 4, 0
1776, 7, 4, 1
1776, 7, 14, 0
1776, 7, 14, 1
1776, 7, 23, 0
1776, 7, 23, 1
1776, 12, 4, 0
1776, 12, 4, 1
1776, 12, 14, 0
1776, 12, 14, 1
1776, 12, 23, 0
1776, 12, 23, 1
1789, 7, 4, 0
1789, 7, 4, 1
1789, 7, 14, 0
1789, 7, 14, 1
1789, 7, 23, 0
1789, 7, 23, 1
1789, 12, 4, 0
1789, 12, 4, 1
1789, 12, 14, 0
1789, 12, 14, 1
1789, 12, 23, 0
1789, 12, 23, 1

 (1, 2, 3) * (30) * (500, 100)
1, 30, 500
1, 30, 100
2, 30, 500
2, 30, 100
3, 30, 500
3, 30, 100

 (1, 2, 3) * () * (500, 100)

Racket

Racket has a built-in "cartesian-product" function:

#lang racket/base
(require rackunit
         ;; usually, included in "racket", but we're using racket/base so we
         ;; show where this comes from
         (only-in racket/list cartesian-product))
;; these tests will pass silently
(check-equal? (cartesian-product '(1 2) '(3 4))
             '((1 3) (1 4) (2 3) (2 4)))
(check-equal? (cartesian-product '(3 4) '(1 2))
             '((3 1) (3 2) (4 1) (4 2)))
(check-equal? (cartesian-product '(1 2) '()) '())
(check-equal? (cartesian-product '() '(1 2)) '())

;; these will print
(cartesian-product '(1776 1789) '(7 12) '(4 14 23) '(0 1))
(cartesian-product '(1 2 3) '(30) '(500 100))
(cartesian-product '(1 2 3) '() '(500 100))
Output:
'((1776 7 4 0)
  (1776 7 4 1)
  (1776 7 14 0)
  (1776 7 14 1)
  (1776 7 23 0)
  (1776 7 23 1)
  (1776 12 4 0)
  (1776 12 4 1)
  (1776 12 14 0)
  (1776 12 14 1)
  (1776 12 23 0)
  (1776 12 23 1)
  (1789 7 4 0)
  (1789 7 4 1)
  (1789 7 14 0)
  (1789 7 14 1)
  (1789 7 23 0)
  (1789 7 23 1)
  (1789 12 4 0)
  (1789 12 4 1)
  (1789 12 14 0)
  (1789 12 14 1)
  (1789 12 23 0)
  (1789 12 23 1))
'((1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100))
'()

Raku

(formerly Perl 6)

Works with: Rakudo version 2017.06

The cross meta operator X will return the cartesian product of two lists. To apply the cross meta-operator to a variable number of lists, use the reduce cross meta operator [X].

# cartesian product of two lists using the X cross meta-operator
say (1, 2) X (3, 4);
say (3, 4) X (1, 2);
say (1, 2) X ( );
say ( )    X ( 1, 2 );

# cartesian product of variable number of lists using
# the [X] reduce cross meta-operator
say [X] (1776, 1789), (7, 12), (4, 14, 23), (0, 1);
say [X] (1, 2, 3), (30), (500, 100);
say [X] (1, 2, 3), (),   (500, 100);
Output:
((1 3) (1 4) (2 3) (2 4))
((3 1) (3 2) (4 1) (4 2))
()
()
((1776 7 4 0) (1776 7 4 1) (1776 7 14 0) (1776 7 14 1) (1776 7 23 0) (1776 7 23 1) (1776 12 4 0) (1776 12 4 1) (1776 12 14 0) (1776 12 14 1) (1776 12 23 0) (1776 12 23 1) (1789 7 4 0) (1789 7 4 1) (1789 7 14 0) (1789 7 14 1) (1789 7 23 0) (1789 7 23 1) (1789 12 4 0) (1789 12 4 1) (1789 12 14 0) (1789 12 14 1) (1789 12 23 0) (1789 12 23 1))
((1 30 500) (1 30 100) (2 30 500) (2 30 100) (3 30 500) (3 30 100))
()

REXX

version 1

This REXX version isn't limited by the number of lists or the number of sets within a list.

/*REXX program  calculates  the   Cartesian product   of two  arbitrary-sized  lists.   */
@.=                                              /*assign the default value to  @. array*/
parse arg @.1                                    /*obtain the optional value of  @.1    */
if @.1=''  then do;  @.1= "{1,2} {3,4}"          /*Not specified?  Then use the defaults*/
                     @.2= "{3,4} {1,2}"          /* "      "         "   "   "      "   */
                     @.3= "{1,2} {}"             /* "      "         "   "   "      "   */
                     @.4= "{}    {3,4}"          /* "      "         "   "   "      "   */
                     @.5= "{1,2} {3,4,5}"        /* "      "         "   "   "      "   */
                end
                                                 /* [↓]  process each of the  @.n values*/
  do n=1  while @.n \= ''                        /*keep processing while there's a value*/
  z= translate( space( @.n, 0),  ,  ',')         /*translate the  commas  to blanks.    */
     do #=1  until z==''                         /*process each elements in first list. */
     parse var  z   '{'  x.#  '}'   z            /*parse the list  (contains elements). */
     end   /*#*/
  $=
     do       i=1   for #-1                      /*process the subsequent lists.        */
       do     a=1   for words(x.i)               /*obtain the elements of the first list*/
         do   j=i+1 for #-1                      /*   "    "  subsequent lists.         */
           do b=1   for words(x.j)               /*   "    " elements of subsequent list*/
           $=$',('word(x.i, a)","word(x.j, b)')' /*append partial Cartesian product ──►$*/
           end   /*b*/
         end     /*j*/
       end       /*a*/
     end         /*i*/
  say 'Cartesian product of '       space(@.n)       " is ───► {"substr($, 2)'}'
  end            /*n*/                           /*stick a fork in it,  we're all done. */
output   when using the default lists:
Cartesian product of  {1,2} {3,4}  is ───► {(1,3),(1,4),(2,3),(2,4)}
Cartesian product of  {3,4} {1,2}  is ───► {(3,1),(3,2),(4,1),(4,2)}
Cartesian product of  {1,2} {}  is ───► {}
Cartesian product of  {} {3,4}  is ───► {}
Cartesian product of  {1,2} {3,4,5}  is ───► {(1,3),(1,4),(1,5),(2,3),(2,4),(2,5)}

version 2

/* REXX computes the Cartesian Product of up to 4 sets */
Call cart '{1, 2} x {3, 4}'
Call cart '{3, 4} x {1, 2}'
Call cart '{1, 2} x {}'
Call cart '{} x {1, 2}'
Call cart '{1776, 1789} x {7, 12} x {4, 14, 23} x {0, 1}'
Call cart '{1, 2, 3} x {30} x {500, 100}'
Call cart '{1, 2, 3} x {} x {500, 100}'
Exit

cart:
  Parse Arg sl
  Say sl
  Do i=1 By 1 while pos('{',sl)>0
    Parse Var sl '{' list '}' sl
    Do j=1 By 1 While list<>''
      Parse Var list e.i.j . ',' list
      End
    n.i=j-1
    If n.i=0 Then Do /* an empty set */
      Say '{}'
      Say ''
      Return
      End
    End
  n=i-1
  ct2.=0
  Do i=1 To n.1
    Do j=1 To n.2
      z=ct2.0+1
      ct2.z=e.1.i e.2.j
      ct2.0=z
      End
    End
  If n<3 Then
    Return output(2)
  ct3.=0
  Do i=1 To ct2.0
    Do k=1 To n.3
      z=ct3.0+1
      ct3.z=ct2.i e.3.k
      ct3.0=z
      End
    End
  If n<4 Then
    Return output(3)
  ct4.=0
  Do i=1 To ct3.0
    Do l=1 To n.4
      z=ct4.0+1
      ct4.z=ct3.i e.4.l
      ct4.0=z
      End
    End
  Return output(4)

output:
  Parse Arg u
  Do v=1 To value('ct'u'.0')
    res='{'translate(value('ct'u'.'v),',',' ')'}'
    Say res
    End
  Say ' '
  Return 0
Output:
{1, 2} x {3, 4}
{1,3}
{1,4}
{2,3}
{2,4}

{3, 4} x {1, 2}
{3,1}
{3,2}
{4,1}
{4,2}

{1, 2} x {}
{}

{} x {1, 2}
{}

{1776, 1789} x {7, 12} x {4, 14, 23} x {0, 1}
{1776,7,4,0}
{1776,7,4,1}
{1776,7,14,0}
{1776,7,14,1}
{1776,7,23,0}
{1776,7,23,1}
{1776,12,4,0}
{1776,12,4,1}
{1776,12,14,0}
{1776,12,14,1}
{1776,12,23,0}
{1776,12,23,1}
{1789,7,4,0}
{1789,7,4,1}
{1789,7,14,0}
{1789,7,14,1}
{1789,7,23,0}
{1789,7,23,1}
{1789,12,4,0}
{1789,12,4,1}
{1789,12,14,0}
{1789,12,14,1}
{1789,12,23,0}
{1789,12,23,1}

{1, 2, 3} x {30} x {500, 100}
{1,30,500}
{1,30,100}
{2,30,500}
{2,30,100}
{3,30,500}
{3,30,100}

{1, 2, 3} x {} x {500, 100}
{}

Ring

# Project : Cartesian product of two or more lists

list1 = [[1,2],[3,4]]
list2 = [[3,4],[1,2]]
cartesian(list1)
cartesian(list2)

func cartesian(list1)
     for n = 1 to len(list1[1])
         for m = 1 to len(list1[2])
             see "(" + list1[1][n] + ", " + list1[2][m] + ")" + nl
         next
      next
      see nl

Output:

(1, 3)
(1, 4)
(2, 3)
(2, 4)

(3, 1)
(3, 2)
(4, 1)
(4, 2)

RPL

≪ → a b
  ≪ { }
     IF a SIZE b SIZE AND THEN 
        1 a SIZE FOR j 
           1 b SIZE FOR k 
              a j GET b k GET 2 →LIST 1 →LIST +
           NEXT
        NEXT
     END
≫ ≫ 'CROIX' STO
{1 2} {3 4} CROIX
{3 4} {1 2} CROIX
{1 2} {} CROIX
{} {1 2} CROIX
Output:
4: {(1 3) (1 4) (2 3) (2 4)}
3: {(3 1) (3 2) (4 1) (4 2)}
2: {}
1: {}

Ruby

"product" is a method of arrays. It takes one or more arrays as argument and results in the Cartesian product:

p [1, 2].product([3, 4]) 
p [3, 4].product([1, 2])
p [1, 2].product([])
p [].product([1, 2]) 
p [1776, 1789].product([7, 12], [4, 14, 23], [0, 1])
p [1, 2, 3].product([30], [500, 100]) 
p [1, 2, 3].product([], [500, 100])
Output:
[[1, 3], [1, 4], [2, 3], [2, 4]]

[[3, 1], [3, 2], [4, 1], [4, 2]] [] [] [[1776, 7, 4, 0], [1776, 7, 4, 1], [1776, 7, 14, 0], [1776, 7, 14, 1], [1776, 7, 23, 0], [1776, 7, 23, 1], [1776, 12, 4, 0], [1776, 12, 4, 1], [1776, 12, 14, 0], [1776, 12, 14, 1], [1776, 12, 23, 0], [1776, 12, 23, 1], [1789, 7, 4, 0], [1789, 7, 4, 1], [1789, 7, 14, 0], [1789, 7, 14, 1], [1789, 7, 23, 0], [1789, 7, 23, 1], [1789, 12, 4, 0], [1789, 12, 4, 1], [1789, 12, 14, 0], [1789, 12, 14, 1], [1789, 12, 23, 0], [1789, 12, 23, 1]] [[1, 30, 500], [1, 30, 100], [2, 30, 500], [2, 30, 100], [3, 30, 500], [3, 30, 100]] []

Rust

fn cartesian_product(lists: &Vec<Vec<u32>>) -> Vec<Vec<u32>> {
    let mut res = vec![];

    let mut list_iter = lists.iter();
    if let Some(first_list) = list_iter.next() {
        for &i in first_list {
            res.push(vec![i]);
        }
    }
    for l in list_iter {
        let mut tmp = vec![];
        for r in res {
            for &el in l {
                let mut tmp_el = r.clone();
                tmp_el.push(el);
                tmp.push(tmp_el);
            }
        }
        res = tmp;
    }
    res
}
 
fn main() {
    let cases = vec![
        vec![vec![1, 2], vec![3, 4]],
        vec![vec![3, 4], vec![1, 2]],
        vec![vec![1, 2], vec![]],
        vec![vec![], vec![1, 2]],
        vec![vec![1776, 1789], vec![7, 12], vec![4, 14, 23], vec![0, 1]],
        vec![vec![1, 2, 3], vec![30], vec![500, 100]],
        vec![vec![1, 2, 3], vec![], vec![500, 100]],
    ];
    for case in cases {
        println!(
            "{}\n{:?}\n",
            case.iter().map(|c| format!("{:?}", c)).collect::<Vec<_>>().join(" × "),
            cartesian_product(&case)
        )
    }
}
Output:
[1, 2] × [3, 4]

[[1, 3], [1, 4], [2, 3], [2, 4]]

[3, 4] × [1, 2] [[3, 1], [3, 2], [4, 1], [4, 2]]

[1, 2] × [] []

[] × [1, 2] []

[1776, 1789] × [7, 12] × [4, 14, 23] × [0, 1] [[1776, 7, 4, 0], [1776, 7, 4, 1], [1776, 7, 14, 0], [1776, 7, 14, 1], [1776, 7, 23, 0], [1776, 7, 23, 1], [1776, 12, 4, 0], [1776, 12, 4, 1], [1776, 12, 14, 0], [1776, 12, 14, 1], [1776, 12, 23, 0], [1776, 12, 23, 1], [1789, 7, 4, 0], [1789, 7, 4, 1], [1789, 7, 14, 0], [1789, 7, 14, 1], [1789, 7, 23, 0], [1789, 7, 23, 1], [1789, 12, 4, 0], [1789, 12, 4, 1], [1789, 12, 14, 0], [1789, 12, 14, 1], [1789, 12, 23, 0], [1789, 12, 23, 1]]

[1, 2, 3] × [30] × [500, 100] [[1, 30, 500], [1, 30, 100], [2, 30, 500], [2, 30, 100], [3, 30, 500], [3, 30, 100]]

[1, 2, 3] × [] × [500, 100] []

Scala

Function returning the n-ary product of an arbitrary number of lists, each of arbitrary length:

def cartesianProduct[T](lst: List[T]*): List[List[T]] = {

  /**
    * Prepend single element to all lists of list
    * @param e single elemetn
    * @param ll list of list
    * @param a accumulator for tail recursive implementation
    * @return list of lists with prepended element e
    */
  def pel(e: T,
          ll: List[List[T]],
          a: List[List[T]] = Nil): List[List[T]] =
    ll match {
      case Nil => a.reverse
      case x :: xs => pel(e, xs, (e :: x) :: a )
    }

  lst.toList match {
    case Nil => Nil
    case x :: Nil => List(x)
    case x :: _ =>
      x match {
        case Nil => Nil
        case _ =>
          lst.par.foldRight(List(x))( (l, a) =>
            l.flatMap(pel(_, a))
          ).map(_.dropRight(x.size))
      }
  }
}

and usage:

cartesianProduct(List(1, 2), List(3, 4))
  .map(_.mkString("(", ", ", ")")).mkString("{",", ","}")
Output:
{(1, 3), (1, 4), (2, 3), (2, 4)}
cartesianProduct(List(3, 4), List(1, 2))
  .map(_.mkString("(", ", ", ")")).mkString("{",", ","}")
Output:
{(3, 1), (3, 2), (4, 1), (4, 2)}
cartesianProduct(List(1, 2), List.empty)
  .map(_.mkString("(", ", ", ")")).mkString("{",", ","}")
Output:
{}
cartesianProduct(List.empty, List(1, 2))
  .map(_.mkString("(", ", ", ")")).mkString("{",", ","}")
Output:
{}
cartesianProduct(List(1776, 1789), List(7, 12), List(4, 14, 23), List(0, 1))
  .map(_.mkString("(", ", ", ")")).mkString("{",", ","}")
Output:
{(1776, 7, 4, 0), (1776, 7, 4, 1), (1776, 7, 14, 0), (1776, 7, 14, 1), (1776, 7, 23, 0), (1776, 7, 23, 1), (1776, 12, 4, 0), (1776, 12, 4, 1), (1776, 12, 14, 0), (1776, 12, 14, 1), (1776, 12, 23, 0), (1776, 12, 23, 1), (1789, 7, 4, 0), (1789, 7, 4, 1), (1789, 7, 14, 0), (1789, 7, 14, 1), (1789, 7, 23, 0), (1789, 7, 23, 1), (1789, 12, 4, 0), (1789, 12, 4, 1), (1789, 12, 14, 0), (1789, 12, 14, 1), (1789, 12, 23, 0), (1789, 12, 23, 1)}
cartesianProduct(List(1, 2, 3), List(30), List(500, 100))
  .map(_.mkString("(", ", ", ")")).mkString("{",", ","}")
Output:
{(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)}
cartesianProduct(List(1, 2, 3), List.empty, List(500, 100))
  .map(_.mkString("[", ", ", "]")).mkString("\n")
Output:
{}

Scheme

(define cartesian-product (lambda (xs ys)
 (if (or (zero? (length xs)) (zero? (length ys)))
     '()
     (fold append (map (lambda (x) (map (lambda (y) (list x y)) ys)) xs)))))

(define nary-cartesian-product (lambda (ls)
 (if (fold (lambda (a b) (or a b)) (map (compose zero? length) ls))
     '()
     (map flatten (fold cartesian-product ls)))))

> (cartesian-product '(1 2) '(3 4))
((1 3) (1 4) (2 3) (2 4))
> (cartesian-product '(3 4) '(1 2))
((3 1) (3 2) (4 1) (4 2))
> (cartesian-product '(1 2) '())
()
> (cartesian-product '() '(1 2))
()
> (nary-cartesian-product '((1 2)(a b)(x y)))
((1 a x) (1 a y) (1 b x) (1 b y) (2 a x) (2 a y) (2 b x) (2 b y))

Sidef

In Sidef, the Cartesian product of an arbitrary number of arrays is built-in as Array.cartesian():

cartesian([[1,2], [3,4], [5,6]]).say
cartesian([[1,2], [3,4], [5,6]], {|*arr| say arr })

Alternatively, a simple recursive implementation:

func cartesian_product(*arr) {

    var c = []
    var r = []

    func {
        if (c.len < arr.len) {
            for item in (arr[c.len]) {
                c.push(item)
                __FUNC__()
                c.pop
            }
        }
        else {
            r.push([c...])
        }
    }()

    return r
}

Completing the task:

say cartesian_product([1,2], [3,4])
say cartesian_product([3,4], [1,2])
Output:
[[1, 3], [1, 4], [2, 3], [2, 4]]
[[3, 1], [3, 2], [4, 1], [4, 2]]

The product of an empty list with any other list is empty:

say cartesian_product([1,2], [])
say cartesian_product([], [1,2])
Output:
[]
[]

Extra credit:

cartesian_product([1776, 1789], [7, 12], [4, 14, 23], [0, 1]).each{ .say }
Output:
[1776, 7, 4, 0]
[1776, 7, 4, 1]
[1776, 7, 14, 0]
[1776, 7, 14, 1]
[1776, 7, 23, 0]
[1776, 7, 23, 1]
[1776, 12, 4, 0]
[1776, 12, 4, 1]
[1776, 12, 14, 0]
[1776, 12, 14, 1]
[1776, 12, 23, 0]
[1776, 12, 23, 1]
[1789, 7, 4, 0]
[1789, 7, 4, 1]
[1789, 7, 14, 0]
[1789, 7, 14, 1]
[1789, 7, 23, 0]
[1789, 7, 23, 1]
[1789, 12, 4, 0]
[1789, 12, 4, 1]
[1789, 12, 14, 0]
[1789, 12, 14, 1]
[1789, 12, 23, 0]
[1789, 12, 23, 1]
say cartesian_product([1, 2, 3], [30], [500, 100])
say cartesian_product([1, 2, 3], [], [500, 100])
Output:
[[1, 30, 500], [1, 30, 100], [2, 30, 500], [2, 30, 100], [3, 30, 500], [3, 30, 100]]
[]

SQL

If we create lists as tables with one column, cartesian product is easy.

-- set up list 1
create table L1 (value integer);
insert into L1 values (1);
insert into L1 values (2);
-- set up list 2
create table L2 (value integer);
insert into L2 values (3);
insert into L2 values (4);
-- get the product
select * from L1, L2;
Output:
     VALUE      VALUE
---------- ----------
         1          3
         1          4
         2          3
         2          4

You should be able to be more explicit should get the same result:

select * from L1 cross join L2;

Product with an empty list works as expected (using the tables created above):

delete from L2;
select * from L1, L2;
Output:
no rows selected

I don't think "extra credit" is meaningful here because cartesian product is so hard-baked into SQL, so here's just one of the extra credit examples (again using the tables created above):

insert into L1 values (3);
insert into L2 values (30);
create table L3 (value integer);
insert into L3 values (500);
insert into L3 values (100);
-- product works the same for as many "lists" as you'd like
select * from L1, L2, L3;
Output:
     VALUE      VALUE      VALUE
---------- ---------- ----------
         1         30        500
         2         30        500
         3         30        500
         1         30        100
         2         30        100
         3         30        100

Standard ML

fun prodList (nil,     _) = nil
  | prodList ((x::xs), ys) = map (fn y => (x,y)) ys @ prodList (xs, ys)

fun naryProdList zs = foldl (fn (xs, ys) => map op:: (prodList (xs, ys))) [[]] (rev zs)
Output:
- prodList ([1, 2], [3, 4]);
val it = [(1,3),(1,4),(2,3),(2,4)] : (int * int) list
- prodList ([3, 4], [1, 2]);
val it = [(3,1),(3,2),(4,1),(4,2)] : (int * int) list
- prodList ([1, 2], []);
stdIn:8.1-8.22 Warning: type vars not generalized because of
   value restriction are instantiated to dummy types (X1,X2,...)
val it = [] : (int * ?.X1) list
- naryProdList [[1776, 1789], [7, 12], [4, 14, 23], [0, 1]];
val it =
  [[1776,7,4,0],[1776,7,4,1],[1776,7,14,0],[1776,7,14,1],[1776,7,23,0],
   [1776,7,23,1],[1776,12,4,0],[1776,12,4,1],[1776,12,14,0],[1776,12,14,1],
   [1776,12,23,0],[1776,12,23,1],[1789,7,4,0],[1789,7,4,1],[1789,7,14,0],
   [1789,7,14,1],[1789,7,23,0],[1789,7,23,1],[1789,12,4,0],[1789,12,4,1],
   [1789,12,14,0],[1789,12,14,1],[1789,12,23,0],[1789,12,23,1]]
  : int list list
- naryProdList [[1, 2, 3], [30], [500, 100]];
val it = [[1,30,500],[1,30,100],[2,30,500],[2,30,100],[3,30,500],[3,30,100]]
  : int list list
- naryProdList [[1, 2, 3], [], [500, 100]];
val it = [] : int list list

Stata

In Stata, the command fillin may be used to expand a dataset with all combinations of a number of variables. Thus it's easy to compute a cartesian product.

. list

     +-------+
     | a   b |
     |-------|
  1. | 1   3 |
  2. | 2   4 |
     +-------+

. fillin a b
. list

     +-----------------+
     | a   b   _fillin |
     |-----------------|
  1. | 1   3         0 |
  2. | 1   4         1 |
  3. | 2   3         1 |
  4. | 2   4         0 |
     +-----------------+

The other way around:

. list

     +-------+
     | a   b |
     |-------|
  1. | 3   1 |
  2. | 4   2 |
     +-------+

. fillin a b
. list

     +-----------------+
     | a   b   _fillin |
     |-----------------|
  1. | 3   1         0 |
  2. | 3   2         1 |
  3. | 4   1         1 |
  4. | 4   2         0 |
     +-----------------+

Note, however, that this is not equivalent to a cartesian product when one of the variables is "empty" (that is, only contains missing values).

. list

     +-------+
     | a   b |
     |-------|
  1. | 1   . |
  2. | 2   . |
     +-------+

. fillin a b
. list

     +-----------------+
     | a   b   _fillin |
     |-----------------|
  1. | 1   .         0 |
  2. | 2   .         0 |
     +-----------------+

This command works also if the varaibles have different numbers of nonmissing elements. However, this requires additional code to remove the observations with missing values.

. list

     +-----------+
     | a   b   c |
     |-----------|
  1. | 1   4   6 |
  2. | 2   5   . |
  3. | 3   .   . |
     +-----------+

. fillin a b c
. list

     +---------------------+
     | a   b   c   _fillin |
     |---------------------|
  1. | 1   4   6         0 |
  2. | 1   4   .         1 |
  3. | 1   5   6         1 |
  4. | 1   5   .         1 |
  5. | 1   .   6         1 |
     |---------------------|
  6. | 1   .   .         1 |
  7. | 2   4   6         1 |
  8. | 2   4   .         1 |
  9. | 2   5   6         1 |
 10. | 2   5   .         0 |
     |---------------------|
 11. | 2   .   6         1 |
 12. | 2   .   .         1 |
 13. | 3   4   6         1 |
 14. | 3   4   .         1 |
 15. | 3   5   6         1 |
     |---------------------|
 16. | 3   5   .         1 |
 17. | 3   .   6         1 |
 18. | 3   .   .         0 |
     +---------------------+

. foreach var of varlist _all {
          quietly drop if missing(`var')
  }

. list

     +---------------------+
     | a   b   c   _fillin |
     |---------------------|
  1. | 1   4   6         0 |
  2. | 1   5   6         1 |
  3. | 2   4   6         1 |
  4. | 2   5   6         1 |
  5. | 3   4   6         1 |
     |---------------------|
  6. | 3   5   6         1 |
     +---------------------+

Swift

Translation of: Scala
func + <T>(el: T, arr: [T]) -> [T] {
  var ret = arr

  ret.insert(el, at: 0)

  return ret
}

func cartesianProduct<T>(_ arrays: [T]...) -> [[T]] {
  guard let head = arrays.first else {
    return []
  }

  let first = Array(head)

  func pel(
    _ el: T,
    _ ll: [[T]],
    _ a: [[T]] = []
  ) -> [[T]] {
    switch ll.count {
    case 0:
      return a.reversed()
    case _:
      let tail = Array(ll.dropFirst())
      let head = ll.first!

      return pel(el, tail, el + head + a)
    }
  }

  return arrays.reversed()
    .reduce([first], {res, el in el.flatMap({ pel($0, res) }) })
    .map({ $0.dropLast(first.count) })
}


print(cartesianProduct([1, 2], [3, 4]))
print(cartesianProduct([3, 4], [1, 2]))
print(cartesianProduct([1, 2], []))
print(cartesianProduct([1776, 1789], [7, 12], [4, 14, 23], [0, 1]))
print(cartesianProduct([1, 2, 3], [30], [500, 100]))
print(cartesianProduct([1, 2, 3], [], [500, 100])
Output:
[[1, 3], [1, 4], [2, 3], [2, 4]]
[[3, 1], [3, 2], [4, 1], [4, 2]]
[]
[[1776, 7, 4, 0], [1776, 7, 4, 1], [1776, 7, 14, 0], [1776, 7, 14, 1], [1776, 7, 23, 0], [1776, 7, 23, 1], [1776, 12, 4, 0], [1776, 12, 4, 1], [1776, 12, 14, 0], [1776, 12, 14, 1], [1776, 12, 23, 0], [1776, 12, 23, 1], [1789, 7, 4, 0], [1789, 7, 4, 1], [1789, 7, 14, 0], [1789, 7, 14, 1], [1789, 7, 23, 0], [1789, 7, 23, 1], [1789, 12, 4, 0], [1789, 12, 4, 1], [1789, 12, 14, 0], [1789, 12, 14, 1], [1789, 12, 23, 0], [1789, 12, 23, 1]]
[[1, 30, 500], [1, 30, 100], [2, 30, 500], [2, 30, 100], [3, 30, 500], [3, 30, 100]]
[]

Tailspin

'{1,2}x{3,4} = $:[by [1,2]..., by [3,4]...];
' -> !OUT::write

'{3,4}x{1,2} = $:[by [3,4]..., by [1,2]...];
' -> !OUT::write

'{1,2}x{} = $:[by [1,2]..., by []...];
' -> !OUT::write

'{}x{1,2} = $:[by []..., by [1,2]...];
' -> !OUT::write

'{1776, 1789} × {7, 12} × {4, 14, 23} × {0, 1} = $:[by [1776, 1789]..., by [7, 12]..., by [4, 14, 23]..., by [0, 1]...];
' -> !OUT::write

'{1, 2, 3} × {30} × {500, 100} = $:[by [1, 2, 3] ..., by [30]..., by [500, 100]...];
' -> !OUT::write

'{1, 2, 3} × {} × {500, 100} = $:[by [1, 2, 3]..., by []..., by [500, 100]...];
' -> !OUT::write

// You can also generate structures with named fields
'year {1776, 1789} × month {7, 12} × day {4, 14, 23} = $:{by [1776, 1789]... -> (year:$), by [7, 12]... -> (month:$), by [4, 14, 23]... -> (day:$)};
' -> !OUT::write
Output:
{1,2}x{3,4} = [1, 3][2, 3][1, 4][2, 4]
{3,4}x{1,2} = [3, 1][4, 1][3, 2][4, 2]
{1,2}x{} = 
{}x{1,2} = 
{1776, 1789} × {7, 12} × {4, 14, 23} × {0, 1} = [1776, 7, 4, 0][1789, 7, 4, 0][1776, 12, 4, 0][1789, 12, 4, 0][1776, 7, 14, 0][1789, 7, 14, 0][1776, 12, 14, 0][1789, 12, 14, 0][1776, 7, 23, 0][1789, 7, 23, 0][1776, 12, 23, 0][1789, 12, 23, 0][1776, 7, 4, 1][1789, 7, 4, 1][1776, 12, 4, 1][1789, 12, 4, 1][1776, 7, 14, 1][1789, 7, 14, 1][1776, 12, 14, 1][1789, 12, 14, 1][1776, 7, 23, 1][1789, 7, 23, 1][1776, 12, 23, 1][1789, 12, 23, 1]
{1, 2, 3} × {30} × {500, 100} = [1, 30, 500][2, 30, 500][3, 30, 500][1, 30, 100][2, 30, 100][3, 30, 100]
{1, 2, 3} × {} × {500, 100} = 
year {1776, 1789} × month {7, 12} × day {4, 14, 23} = {day=4, month=7, year=1776}{day=4, month=7, year=1789}{day=4, month=12, year=1776}{day=4, month=12, year=1789}{day=14, month=7, year=1776}{day=14, month=7, year=1789}{day=14, month=12, year=1776}{day=14, month=12, year=1789}{day=23, month=7, year=1776}{day=23, month=7, year=1789}{day=23, month=12, year=1776}{day=23, month=12, year=1789}

Tcl

proc cartesianProduct {l1 l2} {
  set result {}
  foreach el1 $l1 {
    foreach el2 $l2 {
      lappend result [list $el1 $el2]
    }
  }
  return $result
}

puts "simple"
puts "result: [cartesianProduct {1 2} {3 4}]"
puts "result: [cartesianProduct {3 4} {1 2}]"
puts "result: [cartesianProduct {1 2} {}]"
puts "result: [cartesianProduct {} {3 4}]"

proc cartesianNaryProduct {lists} {
  set result {{}}
  foreach l $lists {
    set res {}
    foreach comb $result {
      foreach el $l {
        lappend res [linsert $comb end $el]
      }
    }
    set result $res
  }
  return $result
}

puts "n-ary"
puts "result: [cartesianNaryProduct {{1776 1789} {7 12} {4 14 23} {0 1}}]"
puts "result: [cartesianNaryProduct {{1 2 3} {30} {500 100}}]"
puts "result: [cartesianNaryProduct {{1 2 3} {} {500 100}}]"
Output:
simple
result: {1 3} {1 4} {2 3} {2 4}
result: {3 1} {3 2} {4 1} {4 2}
result: 
result: 
n-ary
result: {1776 7 4 0} {1776 7 4 1} {1776 7 14 0} {1776 7 14 1} {1776 7 23 0} {1776 7 23 1} {1776 12 4 0} {1776 12 4 1} {1776 12 14 0} {1776 12 14 1} {1776 12 23 0} {1776 12 23 1} {1789 7 4 0} {1789 7 4 1} {1789 7 14 0} {1789 7 14 1} {1789 7 23 0} {1789 7 23 1} {1789 12 4 0} {1789 12 4 1} {1789 12 14 0} {1789 12 14 1} {1789 12 23 0} {1789 12 23 1}
result: {1 30 500} {1 30 100} {2 30 500} {2 30 100} {3 30 500} {3 30 100}
result: 

UNIX Shell

The UNIX shells don't allow passing or returning arrays from functions (other than pass-by-name shenanigans), but as pointed out in the Perl entry, wildcard brace expansion (in bash, ksh, zsh) does a Cartesian product if there's more than one set of alternatives. It doesn't handle the empty-list case (an empty brace expansion item is treated as a single item that is equal to the empty string), but otherwise it works:

   $ printf '%s' "("{1,2},{3,4}")"; printf '\n'
   (1,3)(1,4)(2,3)(2,4)
   $ printf '%s' "("{3,4},{1,2}")"; printf '\n'
   (3,1)(3,2)(4,1)(4,2)

More than two lists is not a problem:

   $ printf '%s\n' "("{1776,1789},{7,12},{4,14,23},{0,1}")"
   (1776,7,4,0)
   (1776,7,4,1)
   (1776,7,14,0)
   (1776,7,14,1)
   (1776,7,23,0)
   (1776,7,23,1)
   (1776,12,4,0)
   (1776,12,4,1)
   (1776,12,14,0)
   (1776,12,14,1)
   (1776,12,23,0)
   (1776,12,23,1)
   (1789,7,4,0)
   (1789,7,4,1)
   (1789,7,14,0)
   (1789,7,14,1)
   (1789,7,23,0)
   (1789,7,23,1)
   (1789,12,4,0)
   (1789,12,4,1)
   (1789,12,14,0)
   (1789,12,14,1)
   (1789,12,23,0)
   (1789,12,23,1)
   $ printf '%s\n' "("{1,2,3},30,{500,100}")"
   (1,30,500)
   (1,30,100)
   (2,30,500)
   (2,30,100)
   (3,30,500)
   (3,30,100)

Visual Basic .NET

Translation of: C#
Imports System.Runtime.CompilerServices

Module Module1

    <Extension()>
    Function CartesianProduct(Of T)(sequences As IEnumerable(Of IEnumerable(Of T))) As IEnumerable(Of IEnumerable(Of T))
        Dim emptyProduct As IEnumerable(Of IEnumerable(Of T)) = {Enumerable.Empty(Of T)}
        Return sequences.Aggregate(emptyProduct, Function(accumulator, sequence) From acc In accumulator From item In sequence Select acc.Concat({item}))
    End Function

    Sub Main()
        Dim empty(-1) As Integer
        Dim list1 = {1, 2}
        Dim list2 = {3, 4}
        Dim list3 = {1776, 1789}
        Dim list4 = {7, 12}
        Dim list5 = {4, 14, 23}
        Dim list6 = {0, 1}
        Dim list7 = {1, 2, 3}
        Dim list8 = {30}
        Dim list9 = {500, 100}

        For Each sequnceList As Integer()() In {
            ({list1, list2}),
            ({list2, list1}),
            ({list1, empty}),
            ({empty, list1}),
            ({list3, list4, list5, list6}),
            ({list7, list8, list9}),
            ({list7, empty, list9})
        }
            Dim cart = sequnceList.CartesianProduct().Select(Function(tuple) $"({String.Join(", ", tuple)})")
            Console.WriteLine($"{{{String.Join(", ", cart)}}}")
        Next
    End Sub

End Module
Output:
{(1, 3), (1, 4), (2, 3), (2, 4)}
{(3, 1), (3, 2), (4, 1), (4, 2)}
{}
{}
{(1776, 7, 4, 0), (1776, 7, 4, 1), (1776, 7, 14, 0), (1776, 7, 14, 1), (1776, 7, 23, 0), (1776, 7, 23, 1), (1776, 12, 4, 0), (1776, 12, 4, 1), (1776, 12, 14, 0), (1776, 12, 14, 1), (1776, 12, 23, 0), (1776, 12, 23, 1), (1789, 7, 4, 0), (1789, 7, 4, 1), (1789, 7, 14, 0), (1789, 7, 14, 1), (1789, 7, 23, 0), (1789, 7, 23, 1), (1789, 12, 4, 0), (1789, 12, 4, 1), (1789, 12, 14, 0), (1789, 12, 14, 1), (1789, 12, 23, 0), (1789, 12, 23, 1)}
{(1, 30, 500), (1, 30, 100), (2, 30, 500), (2, 30, 100), (3, 30, 500), (3, 30, 100)}
{}

Wren

Translation of: Kotlin
Library: Wren-seq
import "./seq" for Lst

var prod2 = Fn.new { |l1, l2|
    var res = []
    for (e1 in l1) {
        for (e2 in l2) res.add([e1, e2])
    }
    return res
}

var prodN = Fn.new { |ll|
    if (ll.count < 2) Fiber.abort("There must be at least two lists.")
    var p2 = prod2.call(ll[0], ll[1])
    return ll.skip(2).reduce(p2) { |acc, l| prod2.call(acc, l) }.map { |l| Lst.flatten(l) }.toList
}

var printProdN = Fn.new { |ll|
    System.print("%(ll.join(" x ")) = ")
    System.write("[\n    ")
    System.print(prodN.call(ll).join("\n    "))
    System.print("]\n")
}

System.print("[1, 2] x [3, 4] = %(prodN.call([ [1, 2], [3, 4] ]))")
System.print("[3, 4] x [1, 2] = %(prodN.call([ [3, 4], [1, 2] ]))")
System.print("[1, 2] x []     = %(prodN.call([ [1, 2], [] ]))")
System.print("[]     x [1, 2] = %(prodN.call([ [], [1, 2] ]))")
System.print("[1, a] x [2, b] = %(prodN.call([ [1, "a"], [2, "b"] ]))")
System.print()
printProdN.call([ [1776, 1789], [7, 12], [4, 14, 23], [0, 1] ])
printProdN.call([ [1, 2, 3], [30], [500, 100] ])
printProdN.call([ [1, 2, 3], [], [500, 100] ])
printProdN.call([ [1, 2, 3], [30], ["a", "b"] ])
Output:
[1, 2] x [3, 4] = [[1, 3], [1, 4], [2, 3], [2, 4]]
[3, 4] x [1, 2] = [[3, 1], [3, 2], [4, 1], [4, 2]]
[1, 2] x []     = []
[]     x [1, 2] = []
[1, a] x [2, b] = [[1, 2], [1, b], [a, 2], [a, b]]

[1776, 1789] x [7, 12] x [4, 14, 23] x [0, 1] = 
[
    [1776, 7, 4, 0]
    [1776, 7, 4, 1]
    [1776, 7, 14, 0]
    [1776, 7, 14, 1]
    [1776, 7, 23, 0]
    [1776, 7, 23, 1]
    [1776, 12, 4, 0]
    [1776, 12, 4, 1]
    [1776, 12, 14, 0]
    [1776, 12, 14, 1]
    [1776, 12, 23, 0]
    [1776, 12, 23, 1]
    [1789, 7, 4, 0]
    [1789, 7, 4, 1]
    [1789, 7, 14, 0]
    [1789, 7, 14, 1]
    [1789, 7, 23, 0]
    [1789, 7, 23, 1]
    [1789, 12, 4, 0]
    [1789, 12, 4, 1]
    [1789, 12, 14, 0]
    [1789, 12, 14, 1]
    [1789, 12, 23, 0]
    [1789, 12, 23, 1]
]

[1, 2, 3] x [30] x [500, 100] = 
[
    [1, 30, 500]
    [1, 30, 100]
    [2, 30, 500]
    [2, 30, 100]
    [3, 30, 500]
    [3, 30, 100]
]

[1, 2, 3] x [] x [500, 100] = 
[
    
]

[1, 2, 3] x [30] x [a, b] = 
[
    [1, 30, a]
    [1, 30, b]
    [2, 30, a]
    [2, 30, b]
    [3, 30, a]
    [3, 30, b]
]

zkl

Cartesian product is build into iterators or can be done with nested loops.

zkl: Walker.cproduct(List(1,2),List(3,4)).walk().println();
L(L(1,3),L(1,4),L(2,3),L(2,4))
zkl: foreach a,b in (List(1,2),List(3,4)){ print("(%d,%d) ".fmt(a,b)) }
(1,3) (1,4) (2,3) (2,4)

zkl: Walker.cproduct(List(3,4),List(1,2)).walk().println();
L(L(3,1),L(3,2),L(4,1),L(4,2))

The walk method will throw an error if used on an empty iterator but the pump method doesn't.

zkl: Walker.cproduct(List(3,4),List).walk().println();
Exception thrown: TheEnd(Ain't no more)

zkl: Walker.cproduct(List(3,4),List).pump(List).println();
L()
zkl: Walker.cproduct(List,List(3,4)).pump(List).println();
L()
zkl: Walker.cproduct(L(1776,1789),L(7,12),L(4,14,23),L(0,1)).walk().println();
L(L(1776,7,4,0),L(1776,7,4,1),L(1776,7,14,0),L(1776,7,14,1),L(1776,7,23,0),L(1776,7,23,1),L(1776,12,4,0),L(1776,12,4,1),L(1776,12,14,0),L(1776,12,14,1),L(1776,12,23,0),L(1776,12,23,1),L(1789,7,4,0),L(1789,7,4,1),L(1789,7,14,0),L(1789,7,14,1),L(1789,7,23,0),L(1789,7,23,1),L(1789,12,4,0),L(1789,12,4,1),...)

zkl: Walker.cproduct(L(1,2,3),L(30),L(500,100)).walk().println();
L(L(1,30,500),L(1,30,100),L(2,30,500),L(2,30,100),L(3,30,500),L(3,30,100))

zkl: Walker.cproduct(L(1,2,3),List,L(500,100)).pump(List).println();
L()