Just wanted to try a variety of methods to a solution. I wanted to do a variety of parallel, plinq, and straight forward logic test. I also wanted to implement a extension method and use func<> for better refactoring. As a test, I considered doing Euler's #1:
http://projecteuler.net/problem=1
Here are the several methods I created:
Method 1: is the straight forward logic I would have used, and seems to be the quickest.
Method 2s: is probably something I would use as well, and to clean code up.
Method 3s: using Parallel programming, doesn't always speed things up. Depends on how much work needs to be done. I used an Extension method called Slice which expands the use of enumerable. I mainly got the idea to do this after reading about extention methods from http://www.blackrabbitcoder.net/archive/2013/03/08/c.net-little-wonders-extension-methods-demystified.aspx
For the Slice Extension, I used this:
The Main program. I hate repeating myself, so after some refactoring I came up with this to use delegates.
http://projecteuler.net/problem=1
Here are the several methods I created:
Code Snippet
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Threading;
- namespace ProjectEuler
- {
- /*
- * Q: If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
- * Find the sum of all the multiples of 3 or 5 below 1000.
- *
- * A: 233168
- *
- * Results:
- Method 1 Avg Time: 0.000007768
- Method 2a Avg Time: 0.000040169
- Method 2b Avg Time: 0.000029314
- Method 2c Avg Time: 0.000347431
- Method 2d Avg Time: 0.000175544
- Method 3a Avg Time: 0.00017445
- Method 3b Avg Time: 0.000144669
- Method 3c Avg Time: 0.002392947
- Method 3d Avg Time: 0.001309331
- *
- */
- class Problem1
- {
- int[] items = Enumerable.Range(1, 999).ToArray();
- ReaderWriterLockSlim rw = new ReaderWriterLockSlim();
- int sum = 0;
- //KISS Logic
- public int RunMethod1()
- {
- sum = 0;
- foreach(int s in items)
- {
- if (s % 3 == 0 || s % 5 == 0)
- {
- sum += s;
- }
- };
- return sum;
- }
- //Lazy Method
- public int RunMethod2a()
- {
- return items.Where(n => n % 3 == 0 || n % 5 == 0).Sum();
- }
- //Lazy Method on the fly
- public int RunMethod2b()
- {
- return Enumerable.Range(1, 999).Where(n => n % 3 == 0 || n % 5 == 0).Sum();
- }
- //Parallel Lazy Method
- public int RunMethod2c()
- {
- return items.AsParallel().Where(n => n % 3 == 0 || n % 5 == 0).Sum();
- }
- //Parallel Lazy Method on the fly
- public int RunMethod2d()
- {
- return Enumerable.Range(1, 999).AsParallel().Where(n => n % 3 == 0 || n % 5 == 0).Sum();
- }
- //Basic Parallel Method
- public int RunMethod3a()
- {
- List<int> multOf3Or5 = new List<int>();
- Parallel.ForEach(items, s =>
- {
- if (s % 3 == 0 || s % 5 == 0)
- {
- lock (multOf3Or5)
- {
- multOf3Or5.Add(s);
- }
- }
- }
- );
- return multOf3Or5.Sum();
- }
- //Parallel it, but slice the work up
- public int RunMethod3b()
- {
- List<int> multOf3Or5 = new List<int>();
- Parallel.ForEach(items.Slice(100), s =>
- {
- foreach (int item in s)
- {
- if (item % 3 == 0 || item % 5 == 0)
- {
- lock (multOf3Or5)
- {
- multOf3Or5.Add(item);
- }
- }
- }
- });
- return multOf3Or5.Sum();
- }
- //Basic Parallel Method just sum it
- public int RunMethod3c()
- {
- sum = 0;
- Parallel.ForEach(items, s =>
- {
- if (s % 3 == 0 || s % 5 == 0)
- {
- rw.EnterWriteLock();
- sum += s;
- rw.ExitWriteLock();
- }
- });
- return sum;
- }
- //Basic Parallel Method just slice & sum it
- public int RunMethod3d()
- {
- sum = 0;
- Parallel.ForEach(items.Slice(100), s =>
- {
- foreach (int item in s)
- {
- if (item % 3 == 0 || item % 5 == 0)
- {
- rw.EnterWriteLock();
- sum += item;
- rw.ExitWriteLock();
- }
- }
- });
- return sum;
- }
- }
- }
Method 1: is the straight forward logic I would have used, and seems to be the quickest.
Method 2s: is probably something I would use as well, and to clean code up.
Method 3s: using Parallel programming, doesn't always speed things up. Depends on how much work needs to be done. I used an Extension method called Slice which expands the use of enumerable. I mainly got the idea to do this after reading about extention methods from http://www.blackrabbitcoder.net/archive/2013/03/08/c.net-little-wonders-extension-methods-demystified.aspx
For the Slice Extension, I used this:
Code Snippet
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace ProjectEuler
- {
- public static class EnumerableExtensions
- {
- //Source and Inspiration: http://www.blackrabbitcoder.net/archive/2013/03/08/c.net-little-wonders-extension-methods-demystified.aspx
- public static IEnumerable<IEnumerable<T>> Slice<T>(this IEnumerable<T> source, int size)
- {
- // can't slice null sequence
- if (source == null) throw new ArgumentNullException("source");
- if (size < 1) throw new ArgumentOutOfRangeException("size", "The size must be positive.");
- // force into a list to take advantage of direct indexing. Could also force into an
- // array, use LINQ grouping, do a Skip()/Take(), etc...
- var sourceList = source.ToList();
- int current = 0;
- // while there are still items to "slice" off, keep going
- while (current < sourceList.Count)
- {
- // return a sub-slice using an iterator for deferred execution
- yield return sourceList.GetRange(current, Math.Min(size, sourceList.Count - current));
- current += size;
- }
- }
- }
- }
The Main program. I hate repeating myself, so after some refactoring I came up with this to use delegates.
Code Snippet
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Diagnostics;
- namespace ProjectEuler
- {
- class Program
- {
- public static Stopwatch sw = new Stopwatch();
- public delegate int fPointer();
- static void Main(string[] args)
- {
- //Initialize Problem(s)
- Problem1 p1 = new Problem1();
- Func<fPointer,int, double> timeIt = (d,runCount) =>
- {
- List<double> times = new List<double>();
- for (int i = 0; i < runCount; i++)
- {
- sw.Reset();
- sw.Start();
- d();
- sw.Stop();
- times.Add(sw.Elapsed.TotalSeconds);
- }
- return times.Average();
- };
- //Get Times of Running Methods
- Console.WriteLine("Method 1 Avg Time: " + timeIt(p1.RunMethod1,100));
- Console.WriteLine("Method 2a Avg Time: " + timeIt(p1.RunMethod2a, 100));
- Console.WriteLine("Method 2b Avg Time: " + timeIt(p1.RunMethod2b, 100));
- Console.WriteLine("Method 2c Avg Time: " + timeIt(p1.RunMethod2c, 100));
- Console.WriteLine("Method 2d Avg Time: " + timeIt(p1.RunMethod2d, 100));
- Console.WriteLine("Method 3a Avg Time: " + timeIt(p1.RunMethod3a, 100));
- Console.WriteLine("Method 3b Avg Time: " + timeIt(p1.RunMethod3b, 100));
- Console.WriteLine("Method 3c Avg Time: " + timeIt(p1.RunMethod3c, 100));
- Console.WriteLine("Method 3d Avg Time: " + timeIt(p1.RunMethod3d, 100));
- Console.ReadKey();
- }
- }
- }
No comments:
Post a Comment