public static IntListList P (IntList L)
P(tail(L)) = P([2,3]) = [[2,3],[3,2]]The question is, how do we combine the head of the list (in this case, 1) to the result we get from finding the permutations of the tail of the list in order to get the final answer? What we need to do is to insert the head of the list into all the spots in each of the lists we get for
P(tail(L))
.
Let's say we have a method called insertNumber
which does this
for us. This is how insertNumber
would workinsertNumber(1,[2,3]) = [[1,2,3],[2,1,3],[2,3,1]] insertNumber(1,[3,2]) = [[1,3,2],[3,1,2],[3,2,1]]In other words, given an integer and an IntList, insertNumber returns an IntListList created by placing the integer into the IntList in each of the possible places in the IntList (i.e. at the beginning, between each element, and at the end). Assuming we have
insertNumber
(more wishful thinking!), the way we can solve our permutations
problem is by creating a mapping function which applies insertNumber
with
the head of our list to the result we get from finding the permutations of the tail of
the list. This is how mapInsertNumber
would workmapInsertNumber(1,[[2,3],[3,2]]) = ILL.append(insertNumber(1,[2,3]), insertNumber(1,[3,2]))Since
insertNumber
gives us an IntListList, we put all the results of applying
insertNumber
to each list in the IntListList by appending them together.
So, our code for permutations so far is the following:// Returns the permutations of a given list of integers. public static IntListList P (IntList L) { if (IL.isEmpty(L)) { // can't just return an empty IntListList or else there will be nothing to prepend on to! return ILL.prepend(IL.empty(),ILL.empty()); } else { // wishful thinking strategy: insert the head of the list // into the answer we get from calculating the permutations of the tail of the list return mapInsertNumber(IL.head(L), P(IL.tail(L))); } } // Returns an IntListList from applying insertNumber of the given integer n // to each IntList in the given IntListList L public static IntListList mapInsertNumber (int n, IntListList L) { if (ILL.isEmpty(L)) { return ILL.empty(); } else { return ILL.append(insertNumber(n, ILL.head(L)), mapInsertNumber(n, ILL.tail(L))); } }
insertNumber
using Wishful ThinkinginsertNumber
ispublic static IntListList insertNumber (int n, IntList L)Let's use the following as our concrete example:
insertNumber(1,[2,3,4]) = [[1,2,3,4],[2,1,3,4],[2,3,1,4],[2,3,4,1]]Using wishful thinking, let's assume that we can find the result for applying
insertNumber
to the tail of the list.insertNumber(1,[3,4]) = [[1,3,4],[3,1,4],[3,4,1]]What do we need to do to the answer to our smaller problem in order to get the answer to our original problem? There are two things that need to be done. We need to get the solution which starts with the integer given. It's the one we get if we add n to the beginning of L which we can do with the following bit of code:
IL.prepend(n,L)The rest of the solutions don't begin with n. What do they begin with? The head of L! In fact, all we need to do is prepend the head of L to each list we get from the result of doing
insertNumber(n,tail(L))
. This is a mapping function so we will call it
mapPrepend
. The way mapPrepend
works is that it takes an integer
and a list of IntLists and it returns the IntListList which results from prepending the integer
to each IntList inside the given IntListList. So, mapPrepend
works like so:mapPrepend(2,[[1,3,4],[3,1,4],[3,4,1]]) = ILL.prepend(IL.prepend(2,[1,3,4]), ILL.prepend(IL.prepend(2,[3,1,4]), ILL.prepend(IL.prepend(2,[3,4,1]), ILL.empty())))
So, our code for the rest of the problem is the following:
// Returns the list of lists which result from inserting a given integer n // into all the possible places in a given IntList L. public static IntListList insertNumber (int n, IntList L) { if (IL.isEmpty(L)) { // if given an empty IntList, we want to create an IntList with n in it // and that will be the single element in the resulting IntListList return ILL.prepend(IL.prepend(n, IL.empty()), ILL.empty()); } else { // implementation of strategy outlined above return ILL.prepend(IL.prepend(n, L), // solution with n at the beginning // solutions starting with the head of the list given mapPrepend(IL.head(L), insertNumber(n, IL.tail(L)))); } } // Returns an IntListList which has the integer n prepended to each // IntList in L. public static IntListList mapPrepend (int n, IntListList L) { if (ILL.isEmpty(L)) { // no lists to prepend an integer to return L; } else { return ILL.prepend(IL.prepend(n, ILL.head(L)), // prepend to first list mapPrepend(n, ILL.tail(L))); // prepend to rest of lists } }