Naming
Use camelCase
for local variable names. And, use a meaningful name if possible.
//var List1 = new List<int>{1,2,3,4,5,6,7,8,9};
var validNumbers = new List<int>{1,2,3,4,5,6,7,8,9};
Use pluralized noun for variable of collection type.
//var combo = ... /*combo contains all possible combinations, not just one*/
var combos
Code
- You don't need to enumerate the numbers 1 to 9. A
Enumerable.Range
will do the job. - The chain of
!exceptions.Contains(x)
is rather inefficient and redundant. You can avoid them by removing the exceptions from the start withIEnumerable.Except
. - You can reuse the same list in your LINQ.
- You can reuse the same name for your lambdas given they are not within the same parentheses. (Not really a big problem)
Result :
var validNumbers = Enumerable.Range(1, 9).Except(exceptions);
var combos = (from a in validNumbers
from b in validNumbers
from b in validNumbers // Cartesian product
where a > b && b > c && // exclude duplicates
a + b + c == target // add up to the target
select new List<int>{ a, b , c})
.OrderByDescending(x => x[0])
.ThenByDescending(x => x[1])
.ThenByDescending(x => x[2]);
In the last 2 blocks of the code, Console.Write
was repeatedly called within the for loop
. You can join them together with String.Join
before printing it to the console.
Results :
foreach(var item in combos)
Console.WriteLine(string.Join("", item));
Console.Write("excluding " + string.Join(" ", exceptions));
Final Code
I've only extractedtarget
and exceptions
to the parameters, as num
ElementCount
is bound by the implementation.
void Main()
{
string buffer;
int target;
//get target
Console.WriteLine(">> Target is ..?");
while(!int.TryParse(buffer = Console.ReadLine(), out target))
Console.WriteLine("\tInvalid input : {0}", buffer);
Console.WriteLine(target);
Console.WriteLine(/*Empty Line*/);
//get exceptions
var validNumbers = Enumerable.Range(1, 9);
IEnumerable<int?> exceptions;
Console.WriteLine(">> Exceptions are ..? (separated with comma like : 1,2,3)");
while(!TryParseExceptions(buffer = Console.ReadLine(), out exceptions))
Console.WriteLine("\tInvalid input : {0}", buffer);
Console.WriteLine(string.Join(" ", exceptions.OrderBy(x => x)));
Console.WriteLine(/*Empty Line*/);
CalculateCombinations(target, exceptions.Select(e => e.Value).Distinct());
}
int? ToNullableInt(string value)
{
int number;
return int.TryParse(value.Trim(), out number) ? (int?)number : null;
}
bool TryParseExceptions(string value, out IEnumerable<int?> exceptions)
{
//const int MinValue = 1, MaxValue = 9;
exceptions = value == ""
? Enumerable.Empty<int?>()
: value.Split(',').Select(ToNullableInt);
return exceptions.All(e => e.HasValue && (1 <= e.Value && e.Value <= 9)); //less verbose but magical...
//return exceptions.All(e => e.HasValue && (MinValue <= e.Value && e.Value <= MaxValue));
}
// Define other methods and classes here
void CalculateCombinations(int target, IEnumerable<int> exceptions)
{
const int ElementCount = 3;
//var target=12;
//var exceptions=new List<int>{9,7,6};
var validNumbers = Enumerable.Range(1, 9).Except(exceptions);
// Make a Cartesian join of the three lists
// Filter out the stuff that we want
// Sort the result from highest to lowest
var combo = (from l1 in validNumbers
from l2 in validNumbers
from l3 in validNumbers // Cartesian product
where l1 > l2 && l2 > l3 && // exclude duplicates
l1 + l2 + l3 == target // add up to the target
select new List<int>{ l1, l2, l3 })
.OrderByDescending(x => x[0])
.ThenByDescending(x => x[1])
.ThenByDescending(x => x[2]);
Console.WriteLine(string.Format("{0}/{1}", target, ElementCount));
foreach(var item in combo)
Console.WriteLine(string.Join("", item));
Console.Write("excluding : " + string.Join(" ", exceptions.OrderBy(x => x)));
}