Last active
August 29, 2015 14:20
-
-
Save neilmayhew/3f8dd2264fe38f9bd6db to your computer and use it in GitHub Desktop.
An example of using C# and LINQ to program in a functional style
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Use the digits 0-9 (once each) to create two numbers by concatenation. (e.g. 152 and 3476980). | |
// What's the highest product you can achieve when these two numbers are multiplied together? | |
using System; | |
using System.Linq; | |
using System.Numerics; | |
using System.Collections.Generic; | |
namespace HighProduct | |
{ | |
using Number = BigInteger; // Type synonym for the type of numbers we're using | |
using Split = Partition<int>; // Type synonym for a particular split of the digits | |
// Extension methods for handling single items as a collection | |
static class Extensions | |
{ | |
public static IEnumerable<T> Single<T>(this T item) | |
{ | |
return Enumerable.Repeat(item, 1); | |
} | |
public static IEnumerable<T> Append<T>(this IEnumerable<T> coll, T item) | |
{ | |
return coll.Concat(Single(item)); | |
} | |
}; | |
// A generic pair of items of the same type | |
public class Pair<T> | |
{ | |
public T left; | |
public T right; | |
public Pair(T l, T r) | |
{ | |
left = l; | |
right = r; | |
} | |
}; | |
// A pair of Numbers representing two factors | |
public class Factors : Pair<Number> | |
{ | |
public Factors(Number l, Number r) : base(l, r) {} | |
public Number product | |
{ | |
get { return left * right; } | |
} | |
}; | |
// A pair of collections representing one possible division of a collection of items | |
public class Partition<T> : Pair<List<T>> | |
{ | |
public Partition() : base(new List<T>(), new List<T>()) {} | |
public Partition(IEnumerable<T> l, IEnumerable<T> r) : base(new List<T>(l), new List<T>(r)) {} | |
// Derive partitions with the item added to the left and the right | |
public IEnumerable<Partition<T>> adjoin(T item) | |
{ | |
return new Partition<T>[] { | |
new Partition<T>( left.Append(item), right ), | |
new Partition<T>( left, right.Append(item) ) | |
}; | |
} | |
// Generate all partitions for a collection of items | |
public static IEnumerable<Partition<T>> allFor(IEnumerable<T> items) | |
{ | |
return items.Aggregate( | |
new Partition<T>().Single(), | |
(ps, item) => ps.SelectMany(p => p.adjoin(item)) | |
); | |
} | |
}; | |
class HighProduct | |
{ | |
static void Main(string[] args) | |
{ | |
int radix = Convert.ToInt32(args[0]); | |
IEnumerable<int> digits = Enumerable.Range(0, radix).Reverse(); | |
IEnumerable<Split> splits = Split.allFor(digits); | |
IEnumerable<Factors> factors = splits.Select(s => toFactors(s, radix)); | |
Number max = factors.Max(p => p.product); | |
IEnumerable<Factors> best = factors.Where(p => p.product == max); | |
foreach (Factors f in best) | |
{ | |
Console.WriteLine("{0} * {1} = {2}", | |
ToStringWithRadix(f.left, radix), ToStringWithRadix(f.right, radix), f.left * f.right); | |
} | |
} | |
// Convert a Split of the digits to the equivalent pair of Numbers | |
public static Factors toFactors(Split s, int radix) | |
{ | |
return new Factors(toNumber(s.left, radix), toNumber(s.right, radix)); | |
} | |
// Convert a collection of digits to a Number | |
public static Number toNumber(IEnumerable<int> digits, int radix) | |
{ | |
return digits.Aggregate<int, Number>(0, (n, d) => n * radix + d); | |
} | |
// Adapted from http://www.pvladov.com/2012/05/decimal-to-arbitrary-numeral-system.html | |
public static string ToStringWithRadix(Number inputNumber, int radix) | |
{ | |
const string Digits = "0123456789abcdefghijklmnopqrstuvwxyz"; | |
if (radix < 2 || radix > Digits.Length) | |
throw new ArgumentException("The radix must be >= 2 and <= " + Digits.Length.ToString()); | |
if (inputNumber == 0) | |
return "0"; | |
Number currentNumber = Number.Abs(inputNumber); | |
int maxChars = currentNumber.ToByteArray().Length * 8 + 1; | |
char[] charArray = new char[maxChars]; | |
int index = maxChars; | |
while (currentNumber != 0) | |
{ | |
int remainder = (int)(currentNumber % radix); | |
charArray[--index] = Digits[remainder]; | |
currentNumber = currentNumber / radix; | |
} | |
if (inputNumber < 0) | |
charArray[--index] = '-'; | |
return new String(charArray, index, maxChars - index); | |
} | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment