> But it is suboptimal in the sense that it uses for loops
Looking at https://news.ycombinator.com/item?id=41897526 caused me to try asking for a solution in a language that doesn't have `for` loops. Since SQL was taken, I tried Prolog:
% Define a predicate to find all positive divisors of N
divisors(N, Divisors) :-
findall(D, (between(1, N, D), N mod D =:= 0), Divisors).
% Define a predicate to generate all combinations of three distinct elements from a list
combination3(List, X, Y, Z) :-
select(X, List, Rest1),
select(Y, Rest1, Rest2),
select(Z, Rest2, _),
X < Y, Y < Z.
% Define a predicate to find triplets (X, Y, Z) such that X*Y*Z = N
find_triplets(N, X, Y, Z) :-
divisors(N, Divisors),
combination3(Divisors, X, Y, Z),
X * Y * Z =:= N.
% Define a predicate to list all the triplets
list_triplets(N) :-
findall((X, Y, Z), find_triplets(N, X, Y, Z), Triplets),
writeln(Triplets).
Run:
?- [a]. list_triplets(108).
[(1,2,54),(1,3,36),(1,4,27),(1,6,18),(1,9,12),(2,3,18),(2,6,9),(3,4,9)]
I'm in love. I both understand what is happening (I
think I would understand it even if I didn't know the task description!) and could easily port optimizations from the previous solution.
Maybe this is the point when being a polyglot developer - knowing tens of programming languages and their characteristics - will finally start paying off.