3

Given an alphabet A = {a,b,c,d,...} of length n, I would like to get all permutations of length r (r < n).

Now I would like to number these permutations, and there should be a reverse mapping.

For example:

A = {a,b,c}, r = 2

ab -> 0
ba -> 1
ac -> 2
ca -> 3
...

How can I achieve this? I have found it for problems which are order-invariant. But I cant apply it to this situation with the order.

Is there some library doing it in python?

nuemlouno
  • 288
  • 1
  • 10
  • Once you've generated the r-permutations in order, you can flop the array to create a dictionary. The keys are the permutations and the values are the old array indices. (Your question implies that you are doing this in O(r!) space.) – kevinlawler Dec 12 '21 at 12:07
  • 1
    If you genuinely need the closed form, see for instance the answers here https://stackoverflow.com/questions/4595928/represent-order-of-permutation-using-an-integer – kevinlawler Dec 12 '21 at 12:41
  • @nuemlouno: Can you confirm that with permutations each element of the alphabet only appears once? And that the translation for one element to a number (n-th element of the alphabet) <-> (n) is trivial in your case? – Sebastian Dec 12 '21 at 13:27
  • You divide the number in a loop by n...n-r+1 and get the element indices (0..n-1) as remainder. The used up elements of the alphabet don't count. E.g. 5 in your example gives 5%3=2; 5/3=1; 1%2=1;1/2=0. The positions from the remainders are 2 and 1, which is cb. Other example: 4%3=1; 4/3=1; 1%2=1; 1/2=0. The positions are 1 and 1, which is bc (for the second letter of the permutation only {a, c} remain, after b is used, so index 1 now is c). – Sebastian Dec 12 '21 at 13:40

2 Answers2

0

Presumably aa is an invalid selection. Since you are dealing from a distinct alphabet, each deal produces a non-intersecting set of permutations. Your list is counted by r! * choose(n,r) which is n!/(n-r)! or n_r or "k-permutations of n elements." The canonical way to number these is lexicographically.

If I were attempting to generate these using a generic library, I would find a way to deal or choose the unrepeated r elements, then produce all permutations on that set of size r. As far as numbering goes, if you can store the permutations lexicographically in an array you can binsearch to find the index. It is possible to reverse the mapping analytically, but realistically, whatever you're doing here is going to have to have small r.

A quick search shows Python's itertools give you two functions you need: combinations and permutations.

kevinlawler
  • 930
  • 1
  • 9
  • 19
0

We know that there are n permutations of length one (where n is the length of the alphabet). Permutations of length r are all of the permutations of length r-1 appended with each of the n elements in the alphabet. There are n^r of these.

Assigning ids permutations is straight-forward, since generating permutations and counting are really the same thing.

Here, in JS, we compute permutations or length r with any array of characters. To illustrate the idea about counting, see the output when the alphabet is the set of digits '0'='9'...

function permute(r, alphabet) {
  if (r === 1) return alphabet
  let result = []
  let r1 = permute(r-1, alphabet)
  for (let p of r1) {
    for (let a of alphabet) {
      result.push(p+a)
    }
  }
  return result
}

const permutations = permute(3, ['a', 'b', 'c', 'd']);
const withIds = permutations.map((value, id) => ({id, value}));
console.log(withIds);

Same thing in python...

def permute(r, alphabet):
    if r == 1: return alphabet
    result = []
    r1 = permute(r-1, alphabet)
    for p in r1:
        for a in alphabet:
            result.append(p+a)
    return result
danh
  • 62,181
  • 10
  • 95
  • 136
  • but where is here the map to the id I am asking for – nuemlouno Dec 12 '21 at 09:49
  • @nuemlouno - Since the results are unique strings, they can be used as their own ids, and so can their positions in an enumeration. I edited to clarify / demonstrate/ – danh Dec 12 '21 at 15:24
  • I see, so for a given n I need this list to get the corresponding permutation? – nuemlouno Dec 12 '21 at 21:14
  • @nuemlouno, yes. If we assign sequential ints (0,1,2,...), we can use N as an array index into the array of enumerated permutations. Or we can use int ids keys in an an object where permutations are the values. Finally (as I wasn't clear enough in explaining in the answer), the ids and the permutations can be understood as really the same thing. All the x-long permutations of y things, is really just like counting for 0 to y^x - 1 in a base x numbering system. – danh Dec 12 '21 at 21:51
  • 1
    As an example in familiar terms: all of the 3-long permutations of the 10 Arabic numerals is really just like counting from 0-999 in a base 10 numbering system: (000, 001, 002, ... 999). That's just as true for base 3, where the "numerals" are "A", "B", "C" – danh Dec 12 '21 at 21:54