Is it possible to create some Linq that generates a List containing all possible combinations of a series of numbers??
If you enter "21" it would generate a list with the elements:
list[0] = "21"
list[1] = "22"
list[2] = "11"
list[3] = "12"
(Not nessesarily in that order)
I understand you can use range to do things like:
List<char> letterRange = Enumerable.Range('a', 'z' - 'a' + 1).Select(i => (Char)i).ToList(); //97 - 122 + 1 = 26 letters/iterations
Which generates the alphabet from a-z. But I can not seem to transfer this knowledge to make a combination generator
I have been able to figure it out with the following code, but it seems way too bulky and I am sure it can be done with a few lines. It really does feel like a bad solution I have made.
Imagine I have called GetAllCombinations("4321")
if it helps
public static String[] GetAllCombinations(String s)
{
var combinations = new string[PossibleCombinations(s.Length)];
int n = PossibleCombinations(s.Length - 1);
for (int i = 0; i < s.Length; i++)
{
String sub;
String[] subs;
if (i == 0)
{
sub = s.Substring(1); //Get the first number
}
else if (i == s.Length - 1)
{
sub = s.Substring(0, s.Length - 1);
}
else
{
sub = s.Substring(0, i) + s.Substring(i + 1);
}
subs = GetAllCombinations(sub);
for (int j = 0; j < subs.Length; j++)
{
combinations[i * n + j] = s[i] + subs[j];
}
}
return combinations;
}
public static int PossibleCombinations(int n) //Combination possibilities. e.g 1-2-3-4 have 24 different combinations
{
int result = 1;
for (int i = 1; i <= n; i++)
result *= i;
return result;
}
For what it's worth, try something like this:
public static IEnumerable<string> GetPermutations(string s)
{
if (s.Length > 1)
return from ch in s
from permutation in GetPermutations(s.Remove(s.IndexOf(ch), 1))
select string.Format("{0}{1}", ch, permutation);
else
return new string[] { s };
}
For the record: Josh's answer the generic way:
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> items) {
if (items.Count() > 1) {
return items.SelectMany(item => GetPermutations(items.Where(i => !i.Equals(item))),
(item, permutation) => new[] { item }.Concat(permutation));
} else {
return new[] {items};
}
}
Here is my Permutation and Combination function using Linq
public static IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> source, TSource item)
{
if (source == null)
throw new ArgumentNullException("source");
yield return item;
foreach (var element in source)
yield return element;
}
public static IEnumerable<IEnumerable<TSource>> Permutate<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
throw new ArgumentNullException("source");
var list = source.ToList();
if (list.Count > 1)
return from s in list
from p in Permutate(list.Take(list.IndexOf(s)).Concat(list.Skip(list.IndexOf(s) + 1)))
select p.Prepend(s);
return new[] { list };
}
public static IEnumerable<IEnumerable<TSource>> Combinate<TSource>(this IEnumerable<TSource> source, int k)
{
if (source == null)
throw new ArgumentNullException("source");
var list = source.ToList();
if (k > list.Count)
throw new ArgumentOutOfRangeException("k");
if (k == 0)
yield return Enumerable.Empty<TSource>();
foreach (var l in list)
foreach (var c in Combinate(list.Skip(list.Count - k - 2), k - 1))
yield return c.Prepend(l);
}
For the DNA alphabet 'A', 'C', 'G', 'T':
var dna = new[] {'A', 'C', 'G', 'T'};
foreach (var p in dna.Permutate())
Console.WriteLine(String.Concat(p));
gives
ACGT ACTG AGCT AGTC ATCG ATGC CAGT CATG CGAT CGTA CTAG CTGA GACT GATC GCAT GCTA GTAC GTCA TACG TAGC TCAG TCGA TGAC TGCA
and the combinations (k = 2) of DNA alphabet
foreach (var c in dna.Combinate(2))
Console.WriteLine(String.Concat(c));
are
AA AC AG AT CA CC CG CT GA GC GG GT TA TC TG TT
What you're looking for are actually permutations. In short, permutations means that order is relevant (ie, 12 is different from 21) whereas a combination means order is irrelevant (12 and 21 are equivalent). For more information see Wikipedia.
See this thread.
As for doing is in pure LINQ, that sounds like using LINQ for the sake of using LINQ.
As others have pointed out the solutions on this page will generate duplicates if any of the elements are the same. The Distinct() extension will remove them, but it's not very scalable as it will usually result in the entire search tree being traversed anyway. You'll trim the search space considerably by invoking it during traversal:
private static IEnumerable<string> Permute(string str)
{
if (str.Length == 0)
yield return "";
else foreach (var index in str.Distinct().Select(c => str.IndexOf(c)))
foreach (var p in Permute(str.Remove(index, 1)))
yield return str[index] + p;
}
For the example string "bananabana" this results in 8,294 nodes being visited, as opposed to the 9,864,101 visited when you don't do traversal culling.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With