Haskell (Lambdabot), 92 85 bytes
x#y|x==y=[[x]]|1>0=(guard(mod x y<1)>>(y:).map(y*)<$>div x y#2)++x#(y+1)
map(1:).(#2)
Needs Lambdabot Haskell since guard
requires Control.Monad
to be imported. Main function is an anonymous function, which I'm told is allowed and it shaves off a couple of bytes.
Thanks to Laikoni for saving seven bytes.
Explanation:
Monads are very handy.
x # y
This is our recursive function that does all the actual work. x
is the number we're accumulating over (the product of the divisors that remain in the value), and y
is the next number we should try dividing into it.
| x == y = [[x]]
If x
equals y
then we're done recursing. Just use x
as the end of the current gozinta chain and return it.
| 1 > 0 =
Haskell golf-ism for "True". That is, this is the default case.
(guard (mod x y < 1) >>
We're operating inside the list monad now. Within the list monad, we have the ability to make multiple choices at the same time. This is very helpful when finding "all possible" of something by exhaustion. The guard
statement says "only consider the following choice if a condition is true". In this case, only consider the following choice if y
divides x
.
(y:) . map (y *) <$> div x y#2)
If y
does divide x
, we have the choice of adding y
to the gozinta chain. In this case, recursively call (#)
, starting over at y = 2
with x
equal to x / y
, since we want to "factor out" that y
we just added to the chain. Then, whatever the result from this recursive call, multiple its values by the y
we just factored out and add y
to the gozinta chain officially.
++
Consider the following choice as well. This simply adds the two lists together, but monadically we can think of it as saying "choose between doing this thing OR this other thing".
x # (y + 1)
The other option is to simply continue recursing and not use the value y
. If y
does not divide x
then this is the only option. If y
does divide x
then this option will be taken as well as the other option, and the results will be combined.
map (1 :) . (# 2)
This is the main gozinta function. It begins the recursion by calling (#)
with its argument. A 1
is prepended to every gozinta chain, because the (#)
function never puts ones into the chains.
4Welcome to PPCG. Nice first question! – AdmBorkBork – 2017-08-15T17:57:16.887
5"On the off-chance it exists [(looking at you, Mathematica!)]" – Erik the Outgolfer – 2017-08-15T17:59:22.483
@AdmBorkBork I had assumed
[[1]]
, but when faced with @EriktheOutgolfer's answer of[1,1]
I was at a loss for a reason to rule one way or the other. I can't find a definitive answer online and am content to defer to @MrXcoder's suggestion to leave it open, until someone turns up an authoritative answer, or compelling reason or convention from the community. – Umbrella – 2017-08-15T18:04:14.020Can the chains be output in reverse, e.g
[12,6,2,1]
– H.PWiz – 2017-08-15T18:08:59.707On the other hand, would it be more interesting to require
[[1]]
? Or does the community dislike special cases? – Umbrella – 2017-08-15T18:09:25.927@H.PWiz No, ascending within chains. – Umbrella – 2017-08-15T18:09:52.570
@AdmBorkBork It's in the sandbox, we just missed that. I've taken your advice and removed
1
as an input. – Umbrella – 2017-08-15T18:13:08.1303As AdmBorkBork said, edge-cases are generally added only if they are important to the core of the challenge - if you want a reason for only
[[1]]
I'd say that if[1,1]
is a gozinta of1
then[1,1,12]
is a gozinta of12
as is[1,1,1,12]
and now we can no longer "return all..." – Jonathan Allan – 2017-08-15T18:15:34.180@JonathanAllan 1 isn't going to be ever input. – Erik the Outgolfer – 2017-08-15T18:21:17.920
@JonathanAllan Looking into it further, I'm with you: I realize a gozinta chain is a factor chain and
1
doesn't factor to1,1
, just1
. That said, I already made the call and there's 5 answers posted, so it is what it is. – Umbrella – 2017-08-15T18:55:41.7804You should make the pun clear in the question for those who don't know it.
2|4
is read "two goes into four" aka "two gozinta four". – mbomb007 – 2017-08-15T21:45:14.3001
Two and a half hours is not enough time for the sandbox to work. See the sandbox FAQ.
– Peter Taylor – 2017-08-15T22:22:08.643@PeterTaylor Thank you. I had not seen that. I'm finding it very difficult to find rules and guidelines here as they all seem scattered in this thread and that. Is there an index thread? – Umbrella – 2017-08-16T13:10:30.297
Not as such, but the [meta-tag:faq] tag should be a good start. – Peter Taylor – 2017-08-16T13:28:18.700