Reputation: 267
I'd like to get all possible permutations of numbers in an array - n!/k! whereas n is the size of the array and k the number of identical numbers.
For example, there would be 3 (3!/2!) possible permutations of [3,0,0]:
Another example would be [2,1,0], which would yield 6 (3!/1!) permutations:
I've been successfully using code from here:
static IEnumerable<IEnumerable<T>>
GetPermutationsWithRept<T>(IEnumerable<T> list, int length)
{
if (length == 1) return list.Select(t => new T[] { t });
return GetPermutationsWithRept(list, length - 1)
.SelectMany(t => list,
(t1, t2) => t1.Concat(new T[] { t2 }));
}
After generating the permutations, I would run Sum()
to validate each permutation. This, however, might not be a efficient solution. Is there another way to achieve this?
Upvotes: 3
Views: 5678
Reputation: 27861
Using Sum
to filter the output of GetPermutationsWithRept
is not correct. Consider this case:
{1,2,3}
One of the outputs of GetPermutationsWithRept
in this case would be {2,2,2}. The sums are equal (2+2+2 = 1+2+3). However, {2,2,2} is not a valid output.
Here is a solution that builds on your method:
This class is used to compare output items (to calculate distinct results):
public class EnumerableComparer<T> : IEqualityComparer<IEnumerable<T>>
{
public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(IEnumerable<T> obj)
{
return string.Join("-", obj.Select(x => x.ToString())).GetHashCode();
}
}
The following code calls the GetPermutationsWithRept
, and filters the results two times. The first time to remove invalid items like {3,3,3} ad {2,2,2}, and the second time to remove duplicates.
var list = new int[] {1, 2, 3};
var result1 = GetPermutationsWithRept(list, 3).ToList();
var sorted_list = list.OrderBy(item => item).ToList();
var result2 = result1
.Where(rlist => rlist.OrderBy(x => x).SequenceEqual(sorted_list)) //first filter
.Distinct(new EnumerableComparer<int>()) //second filter
.ToList();
I think that in terms of performance, this solution wouldn't be great for large inputs, but it is correct.
Upvotes: 1
Reputation: 845
The function takes a string of characters, and writes down every possible permutation of that exact string, so for example, if "ABC" has been supplied, should spill out:
ABC, ACB, BAC, BCA, CAB, CBA.
Code:
class Program
{
private static void Swap(ref char a, ref char b)
{
if (a == b) return;
a ^= b;
b ^= a;
a ^= b;
}
public static void GetPer(char[] list)
{
int x = list.Length - 1;
GetPer(list, 0, x);
}
private static void GetPer(char[] list, int k, int m)
{
if (k == m)
{
Console.Write(list);
}
else
for (int i = k; i <= m; i++)
{
Swap(ref list[k], ref list[i]);
GetPer(list, k + 1, m);
Swap(ref list[k], ref list[i]);
}
}
static void Main()
{
string str = "abc";
char[] arr = str.ToCharArray();
GetPer(arr);
}
}
Upvotes: 0