public static CombinatorResult <T> Generate <T>(List <T> elements, CombinatorOptions options) { // figure out what is the combinations' length? If not specified, or each element can only occur once // per combination, we use the elements count. Otherwise as specified per the options. var cLength = options.Length == 0 || options.IsElementUnique ? elements.Count : options.Length; // get the combinations. This returns a full set by default var combos = options.IsFullSet ? GetCombinationsFullSet(elements, cLength) : GetCombinationsSparseSet(elements, cLength); //// if not a full set, only return the combinations which are of the specified length //if(!options.IsFullSet) // combos = combos.Where(r => r.Count == cLength).ToList(); // filter out combinations which include duplicate elements if (options.IsElementUnique) { combos = combos.Where(r => r.GroupBy(e => e).All(g => g.Count() == 1)).ToList(); } // filter out combinations which contain the same elements, e.g. 'ab' is the same as 'ba' // note; identifying similar combinations by sum of hashcodes only works for strings. // not ideal given the method is generic, would like to fix this.. maybe hashsets..? if (!options.IsOrdered) { combos = combos.Select(l => (l: l, h: l.Sum(e => (long)e.GetHashCode()))) .GroupBy(t => t.h) .Select(g => g.First().l).ToList(); } return(new CombinatorResult <T> { Result = combos }); }
public override string SolvePart1( ) { var options = new CombinatorOptions { IsFullSet = true, IsElementUnique = true, IsOrdered = false }; var result = Combinator.Generate(new List <string> { "0", "1", "2", "3", "4" }, options) .Select(r => r.Select(int.Parse)) .Select(l => l.Aggregate(0d, (sum, d) => sum += containers[d])) .Count(sum => sum == Liters); return(result.ToString( )); }