Is there any algorithm available for this one :
From a group of characters like :
a,@,n,M,O,f,D,),`,~,;,N,*,8,2,],2........ goes one . There are abou
UPDATE: Here is a working python version of combinations without repetitions:
def ncombs(n,k):
if n < 0 or k < 0 or k > n: return 0
b = 1
for i in xrange(k): b = b*(n-i)/(i+1)
return b
def nthresh(k, idx):
"""Finds the largest value m such that C(m, k) <= idx."""
mk = k
while ncombs(mk, k) <= idx:
mk += 1
return mk - 1
def rank_to_comb(k, rank):
ret = []
for i in range(k, 0, -1):
element = nthresh(i, rank)
ret.insert(0, element)
rank -= ncombs(element, i)
return ret
def random_combination(choices, n):
num_combinations = ncombs(len(choices), n)
desired_rank = random.randint(0, num_combinations-1)
indices = idx_to_set(n, desired_rank)
return [choices[i] for i in indices]
Sample usage:
>>> random_combination("abcdefghijkl", 3)
['b', 'd', 'h']
>>> random_combination("abcdefghijkl", 3)
['b', 'd', 'g']
>>> random_combination("abcdefghijkl", 3)
['d', 'f', 'i']
>>> random_combination("abcdefghijkl", 3)
['d', 'f', 'h']
>>> random_combination("abcdefghijkl", 3)
['b', 'c', 'e']
>>> random_combination("abcdefghijkl", 3)
['c', 'i', 'l']
>>> random_combination("abcdefghijkl", 3)
['c', 'g', 'j']
>>> random_combination("abcdefghijkl", 3)
['b', 'j', 'l']
It works by generating the rank of the desired combination, then generating the combination from the rank, then using that to index into the list of choices. By doing so you guarantee an even distribution of indices (so you don't generate any one combination more often than others).
For example, if you wanted to choose 5 elements from a list of 10, there are 10 C 5
= 252
possible combinations. The first combination is (0, 1, 2, 3, 4)
, the second is (0, 1, 2, 3, 5)
, the third is (0, 1, 2, 4, 5)
, etc... The rank_to_comb
function accomplishes the translation:
>>> rank_to_comb(5, 0)
[0, 1, 2, 3, 4]
>>> rank_to_comb(5, 1)
[0, 1, 2, 3, 5]
>>> rank_to_comb(5, 2)
[0, 1, 2, 4, 5]
>>> rank_to_comb(5, 250)
[4, 6, 7, 8, 9]
>>> rank_to_comb(5, 251)
[5, 6, 7, 8, 9]
So we just uniformly pick a number from 0 to 251, get the combination, index into the choices list, and we're done!
This is the old version that generated permutations, not combinations:
Here is how to generate one combination:
public static String comboFrom(String possibleChars, int charsToTake) {
//randomly shuffle the chars using Collections.shuffle
List<Character> chars = new ArrayList<Character>(possibleChars.length());
for (char c : possibleChars.toCharArray()) {
chars.add(new Character(c));
}
Collections.shuffle(chars);
//Take the first 'charsToTake' characters - these will be totally random
//thanks to the shuffle
String result = "";
int taken=0;
for (Character c : chars) {
result += c.charValue();
if (taken >= charsToTake) break;
taken += 1;
}
return result;
}
Sample usage:
for (int i=0; i < 30; i++) {
System.out.println(comboFrom("abcdefghijkl@#%", 5));
}
Resulted in:
ecjlaf
bi@hfj
ia@#e%
icfad@
kb#gei
ik%@de
ib%jkf
flgb@#
gd@ekc
jedhi#
f@%ckj
lig%#j
l%fki#
ajgdlc
adkbe@
gb@cid
#efcag
@lihkc
k@j%#c
cgkaji
ecb@hj
k@lf%a
gd%fbh
c%lajf
e@#cid
%gfeb#
#%ahcf
be@flj
albjk@
calh%g
You can just call this function repeatedly and stop when you get a result that satisfies your needs. Here is the full code I used.
EDIT: And sorry for this plug but this was so much more annoying to do than I thought that I'm glad I'm using Python at my job:
import random
def comboFrom(possibleChars, charsToTake):
chars = list(possibleChars)
random.shuffle(chars)
return "".join(chars[:charsToTake])
First be aware that the number of possible permutations is in O(n^k)
(Choose(n,k) = n!/(k!*(n-k)!)
to be exact) where n
is the number of characters and k
is the desired length. Since it is exponential it could easily grow out of reach.
A general algorithm for achieving these combinations is using recursion and explore all possibilites up to this length. At each level you "guess" which character you will use next, place it, remove it from the list of available chars and recurse to solve the smaller problem (finding permutation up to length-1
).
private static void printPermutations(char[] chars, int idx, List<Character> candidate, int length) {
if (length == candidate.size()) {
System.out.println(candidate);
return;
}
for (int i = idx; i < chars.length; i++) {
candidate.add(chars[i]);
//set the selected element out of reach:
char temp = chars[idx];
chars[idx] = chars[i];
chars[i] = temp;
//recurse:
printPermutations(chars, idx+1, candidate, length);
//clean up environment:
temp = chars[i];
chars[i] = chars[idx];
chars[idx] = temp;
candidate.remove(candidate.size()-1);
}
}
public static void printPermutations(char[] chars, int length) {
printPermutations(chars, 0, new LinkedList<Character>(), length);
}