I visit a lot of customers and look at a lot of code. I also worked with a number of large production code bases in my previous jobs and I see a lot of ifs, fors and switches. I see loops inside of loops with ifs inside them, all doing various transformations of data from one form to another. I see strings getting parsed to pull bits of data out in ways that are easy to say in English but take 100 lines to say in code.
Should they? When we are just getting started programming we learn about if first, then for, then the much abused switch statement.
I saw this little snippet on Miguel's blog a few weeks ago:
var biggerThan10 = new List;for (int i = 0; i < array.Length; i++){ if (array [i] > 10) biggerThan10.Add (array[i]);}
It's straightforward. Take an array of ints and make a new list with those that are larger than 10. We've all see code like this a million times. Here's the same thing in a few other languages.
C#
var a = from x in array where x > 10 select x; var b = array.Where(x => x > 10);
Ruby
a = array.select{|x| x >10}
JavaScript
a = array.filter(function(x){return x > 10});
I'd much rather write these one line operations than the loop and if above. I still see this out in the world, so perhaps people haven't seen enough examples. I asked friends on Twitter to submit their examples. Thank you Twitter friends!
Here's a few nice examples. Iron Shay has some nice LINQ examples on his blog. Please do share yours in the comments. Be sure to use <pre> tags.
NOTE: This is NOT about "shoving stuff into one line" but rather looking at solutions that are equally as readable but also simpler, terser, and less error prone than loops of loops.
def calculate_primes(n): no_primes = [] primes = [] for i in range(2, 8): for j in range(i*2, n, i): no_primes.append(j) for x in range(2, n): if x not in no_primes: primes.append(x) return primescalculate_primes(500)# Can be like this instead!(lambda n: [x for x in range(2, n) if x not in [j for i in range(2, 8) for j in range(i*2, n, i)]])(500)
From Aaron Bassett
foreach (var i in categories) { foreach (var x in GetAllChildCategories(i.Id)) { yield return x; }}//Can be...return categories.SelectMany(i => this.GetAllChildCategoriesIds(i.Id));
From James Hull
var inputNumbersInString = Console.ReadLine();var inputNumbersStringArray = inputNumbersInString.Split(' ');var inputNumbers = new List<int>();for (int i = 0; i < inputNumbersStringArray.Length; ++i) { inputNumbers.Add(int.Parse(inputNumbersStringArray[i]));}int maxNumber = inputNumbers[0];for (int i = 1; i < inputNumbers.Count; ++i) if (inputNumbers[i] > maxNumber) maxNumber = inputNumbers[i];Console.WriteLine(maxNumber);//Or rather...Console.WriteLine(Console.ReadLine().Split(' ').Select(t => int.Parse(t)).ToList().Max());
From Amit Saraswat
// create a poker deck as a list of two characters strings: // rank, suite char[] figures = "23456789TJQKA".ToCharArray();char[] suites = "SHDC".ToCharArray();List<string> deck = new List<string>();foreach (var figure in figures) { foreach (var suite in suites) { deck.Add(string.Format("{0}{1}", figure, suite)); }}//Or, neatlyvar cards = from r in "23456789TJQKA" from s in "SHDC" select "" + r + s;
From Jack Nova
bool include = false;if (op == Operator.And) { bool current = true; foreach (var item in Items) { current = current & item.Process(); } include = current;}else { bool current = false; foreach (var item in Items) { current = current | item.Process(); } include = current;}return include;//Or this lovely Aggregatereturn op == Operator.And ? Items.Aggregate(true, (current, item) => current & item.Process()) : Items.Aggregate(false, (current, item) => current | item.Process());
From Kevin Meiresonne
sbyte[] sByteArray = new sbyte[100];byte[] uByteArray = new byte[sByteArray.Length];for (int i = 0; i < sByteArray.Length; i++) { uByteArray[i] = (byte)sByteArray[i];}//Or, instead of the loop abovebyte[] uByteArray1 = Array.ConvertAll(sByteArray, x => (byte)x);
From Fahad Mustafa
Scott: I have to say here that I prefer the first option. ;)
// This is the "classic" solution to the FizzBuzz problem.for (int i = 1; i <= 100; i++) { if (i % 3 == 0 && i % 5 == 0) { Console.WriteLine("FizzBuzz"); } else if (i % 3 == 0) { Console.WriteLine("Fizz"); } else if (i % 5 == 0) { Console.WriteLine("Buzz"); } else { Console.WriteLine(i.ToString()); }}// One line Enumerable.Range(1, 100).ToList().ForEach(n => Console.WriteLine((n % 3 == 0) ? (n % 5 == 0) ? "FizzBuzz" : "Fizz" : (n % 5 == 0) ? "Buzz" : n.ToString()));
From Craig Phillips
A good one...I'm surprised more people don't use this.
var temp = String.Empty;foreach (var entry in myStringList) { if (String.IsNullOrEmpty(temp)) { temp = entry; } else { entry += ", " + entry; }}//becomesvar temp = String.Join(", ", myStringList)
From Holger Adam
A class with properties in one line of F#. That'd be a dozen or more lines of C#.
type Person = { Name:string; Age:int }
From Phillip Trelford
/// Input is a string with numbers : 10+20+30+40/// Output is integer with required sum (100)string input = "10+20+30+40";var result = Regex.Split(input, @"\D+").Select(t => int.Parse(t)).Sum();Console.WriteLine("Result is {0}" ,result);
From Srinivas Iyengar
There are a million things available to the programmer beyond the first three keywords we learn. What are your favorite patterns (doesn't matter what language) that have helped you break away from the basics and move to the next level?
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.
// this is just the type declarationquicksort :: Ord a => [a] -> [a]// this says that sorting an empty list yields an empty list// it's useful for terminating the recursion, below. quicksort [] = []// this line *is* the QS algorithm: choose a pivot, then put the lesser // values on one side and the greater (or equal) values on the other// In this case we choose the first item in the list as the pivot// finally, do the same thing recursively on each side of the pivot.quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater) where lesser = filter (< p) xs greater = filter (>= p) xs
if (nrOfDays == 1)return "day"elsereturn "days"
return (nrOfDays == 1) ? "day" : "days";
bool setDefault = p.Objs.Count(x => x.IsDefault) <= 0;
bool setDefault = !p.Objs.Any(x => x.IsDefault);
string[] allItems = { "item1", "item2", "item3" };string[] databaseItems = { "item2" };var data = allItems.SelectMany(item => databaseItems , (item, dbItem) => new { item, dbItem }).Where(x => !x.item.Equals(x.dbItem, StringComparison.InvariantCultureIgnoreCase)).Select(x => x.item);foreach (var v in data)Console.WriteLine(v.ToString());
let array = [| 5..15 |] let a = Array.filter(fun x -> x > 10) array
protected static bool IsSomeBlaBla(IList<Record> records) { bool returnValue = false; if (records != null) { int sundayCount = 0; int mondayCount = 0; int tuesdayCount = 0; int wednesdayCount = 0; int thursdayCount = 0; int fridayCount = 0; int saturdayCount = 0; foreach (Record in records) { switch (record.DayOfWeek) { case DayOfWeek.Sunday: sundayCount++; break; case DayOfWeek.Monday: mondayCount++; break; case DayOfWeek.Tuesday: tuesdayCount++; break; case DayOfWeek.Wednesday: wednesdayCount++; break; case DayOfWeek.Thursday: thursdayCount++; break; case DayOfWeek.Friday: fridayCount++; break; case DayOfWeek.Saturday: saturdayCount++; break; } } returnValue = (sundayCount == 1 & mondayCount == 1 & tuesdayCount == 1 & wednesdayCount == 1 & thursdayCount == 1 & fridayCount == 1 & saturdayCount == 1); } return returnValue; }
protected static bool IsSomeBlaBla(IList<Record> records) { var byDayCounts = (records ?? Enumerable.Empty<Record>()) .GroupBy(record => record.DayOfWeek) .Select(byDays => byDays.Count()) .ToList(); return byDayCounts.Count == 7 && byDayCounts.All(count => count == 1); }
var array = Enumerable.Range(0, 1000).ToArray();// approach 1int c = 0;for (int i = 0; i < array.Length; i++){ if (array[i] > 10) c++;}// approach 2c = array.Count(x => x > 10);
var biggerThan10 = array .Select((x, i) => new { x, i }) .Where(_ => _.x > 10) .Select(_ => _.i);
"This is [not] about "shoving stuff into one line" but rather looking at solutions that are equally as readable but also simpler, terser, and less error prone than loops of loops."
var temp = String.Join(", ", myStringList.ToArray())
var temp = String.Join(", ", myStringList)
/// <summary>/// An implementation of the maybe monad./// </summary>/// <typeparam name="T"></typeparam>public class Maybe<T>{ /// <summary> /// Encapsulates a value. /// </summary> public class Just : Maybe<T> { public T Value { get; private set; } public override string ToString() { return Value.ToString(); } public override int GetHashCode() { return Value.GetHashCode(); } public override bool Equals(object obj) { var other = obj as Just; if (other != null) return other.Value.Equals(this.Value); return false; } public Just(T value) { this.Value = value; } } /// <summary> /// Represents an empty result. /// </summary> public class None : Maybe<T> { public static readonly Maybe<T> Instance = new None(); public override bool Equals(object obj) { return obj is None; } public override int GetHashCode() { return 0; } public override string ToString() { return "None"; } private None() { } }}/// <summary>/// Provides factory and extension methods for the generic maybe class./// </summary>public static class Maybe{ /// <summary> /// Creates a just value. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="value"></param> /// <returns></returns> public static Maybe<T> Just<T>(T value) { return new Maybe<T>.Just(value); } /// <summary> /// Creates an instance of None. /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static Maybe<T> None<T>() { return Maybe<T>.None.Instance; } /// <summary> /// This is to allow the LINQ syntax "from x in m select f(x)" /// </summary> /// <typeparam name="TValue"></typeparam> /// <typeparam name="TResult"></typeparam> /// <param name="x"></param> /// <param name="selector"></param> /// <returns></returns> public static Maybe<TResult> Select<TValue, TResult>(this Maybe<TValue> x, Func<TValue, TResult> selector) { var v = x as Maybe<TValue>.Just; if (v == null) return Maybe.None<TResult>(); return Maybe.Just(selector(v.Value)); } /// <summary> /// This is to allow the LINQ syntax "from x in m from y in n select f(x, y)" /// </summary> /// <typeparam name="TValueA"></typeparam> /// <typeparam name="TValueB"></typeparam> /// <typeparam name="TResult"></typeparam> /// <param name="x"></param> /// <param name="y"></param> /// <param name="selector"></param> /// <returns></returns> public static Maybe<TResult> SelectMany<TValueA, TValueB, TResult>(this Maybe<TValueA> x, Func<TValueA, Maybe<TValueB>> y, Func<TValueA, TValueB, TResult> selector) { var vx = x as Maybe<TValueA>.Just; if (vx == null) return Maybe.None<TResult>(); var vy = y(vx.Value) as Maybe<TValueB>.Just; if (vy == null) return Maybe.None<TResult>(); return Maybe.Just(selector(vx.Value, vy.Value)); } /// <summary> /// If the predicate is satisfied, returs value, otherwise returns none. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="value"></param> /// <param name="predicate"></param> /// <returns></returns> public static Maybe<T> Where<T>(this Maybe<T> value, Func<T, bool> predicate) { if (value.IsNone()) return value; var v = value.GetValue(); if (predicate(v)) return value; return Maybe.None<T>(); } /// <summary> /// Checks if the value is None /// </summary> /// <typeparam name="T"></typeparam> /// <param name="v"></param> /// <returns></returns> public static bool IsNone<T>(this Maybe<T> v) { return v is Maybe<T>.None; } /// <summary> /// Gets the inner value. /// Returns "default(T)" if Maybe is None. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="v"></param> /// <returns></returns> public static T GetValue<T>(this Maybe<T> v) { var t = v as Maybe<T>.Just; if (t != null) return t.Value; return default(T); }}
static Maybe<Tuple<double, double>> Solve(Maybe<double> x, Maybe<double> y, Maybe<double> z){ var s = from a in x from b in y from c in z let det = b * b - 4 * a * c where det >= 0 select Tuple.Create((-b + Math.Sqrt(det)) / (2 * a), (-b - Math.Sqrt(det)) / (2 * a)); return s;}static Maybe<double> ParseDouble(string s){ double v; if (double.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out v)) return Maybe.Just(v); return Maybe.None<double>();}var a = ParseDouble(paramAText);var b = ParseDouble(paramBText);var c = ParseDouble(paramCText);Solve(a, b, c);
grsLSData.Open "SHAPE APPEND New adInteger AS LSID, New adVarChar(20) AS Name_LS, " & _ "SUM(RowData.RowSeatsFilled) AS LSSeatsFilled, SUM(RowData.RowSeatsCount) AS LSSeatsCount," & _ "((SHAPE APPEND New adInteger AS LSID, New adInteger AS RowID, New adVarChar(10) AS Name_Row, " & _ "SUM(SeatData.EventsSeatFilled) AS RowSeatsFilled, SUM(SeatData.EventsSeatCount) AS RowSeatsCount, " & _ "((SHAPE APPEND New adInteger AS RowID, New adInteger AS SeatID, New adVarChar(10) AS Name_Seat, " & _ "SUM(EventSeatData.Filled) AS EventsSeatFilled, COUNT(EventSeatData.Name_EventCode) AS EventsSeatCount, " & _ "((SHAPE APPEND New adInteger AS SeatID, New adVarChar(10) AS Name_EventCode, " & _ "New adVarChar(2) AS Status, New adDouble AS Color, New adInteger AS Filled, New adInteger AS Custom) " & _ "RELATE SeatID to SeatID) AS EventSeatData) " & _ "RELATE RowID to RowID) AS SeatData) " & _ "RELATE LSID TO LSID) AS RowData ", , adOpenStatic, adLockOptimistic
Enumerable.Range(1, 100).Select(n => new { n = n, Fizzy = (n % 3 == 0), Buzzy = (n % 5 == 0) }).Select(fb => new {n = fb.n, Fuzzy = (fb.Fizzy ? "Fizz" : "") + (fb.Buzzy ? "Buzz" : "")}).Select(f => f.Fuzzy.Length > 0 ? f.Fuzzy : f.n.ToString())
var enumerable = Enumerable.Range(0, 9999999);var sw = new Stopwatch();int c = 0;// approach 1sw.Start();var array = enumerable.ToArray();for (int i = 0; i < array.Length; i++){ if (array[i] > 10) c++;}sw.Stop();c.Dump();sw.ElapsedMilliseconds.Dump();// approach 2sw.Restart();c = enumerable.Count(x => x > 10);sw.Stop();c.Dump();sw.ElapsedMilliseconds.Dump();// approach 3sw.Restart();c = enumerable.AsParallel().Where(x => x > 10).Count();sw.Stop();c.Dump();sw.ElapsedMilliseconds.Dump();//Approach 4 - Type Checking?var objectEnum = enumerable.OfType<object>().Concat(new[] { "Hello" });sw.Start();var objectArray = objectEnum.ToArray();for (int i = 0; i < objectArray.Length; i++){ int outVal; var isInt = int.TryParse(objectArray[i].ToString(),out outVal); if (isInt && Convert.ToInt32(objectArray[i]) > 10) c++;}sw.Stop();c.Dump();sw.ElapsedMilliseconds.Dump();// approach 5sw.Restart();c = enumerable.OfType<int>().Count(x => x > 10);sw.Stop();c.Dump();sw.ElapsedMilliseconds.Dump();// approach 6sw.Restart();c = enumerable.AsParallel().OfType<int>().Where(x => x > 10).Count();sw.Stop();c.Dump();sw.ElapsedMilliseconds.Dump();
private Thing _something;public Thing Something { get { if (_something == null) { _something = new Thing(); } return _something; }}
private Thing _something;public Thing Something { get { return _something ?? (_something = new Thing()); } }
var sb = new StringBuilder();var stringArray = new []{"Test1","Test2","Test3"};for(int i=0, count = stringArray.Length;i<count;i++){ if(i==count-1){ sb.Append(stringArray[i]); } else{ sb.Append(stringArray[i] + ","); }}//BecomesstringArray.Aggregate(String.Empty, (current, b) => current + ("," + b)).Substring(1);//Substring used to trim leading ','
private Dictionary<char, Func<Expression, Expression, Expression>> operations = new Dictionary<char, Func<Expression, Expression, Expression>> { { '+', (current, next) => Expression.Add(current, next) }, { '-', (current, next) => Expression.Subtract(current, next) }, { '*', (current, next) => Expression.Multiply(current, next) }, { '/', (current, next) => Expression.Divide(current, next) } }; public decimal Evaluate(string expression){ foreach (var operation in operations) { if (expression.Contains(operation.Key)) { var parts = expression.Split(operation.Key); Expression result = Expression.Constant(Evaluate(parts[0])); result = parts.Skip(1).Aggregate(result, (current, next) => operation.Value(current, Expression.Constant(Evaluate(next)))); var lambda = Expression.Lambda<Func<decimal>>(result); var compiled = lambda.Compile(); return compiled(); } } decimal value = 0; decimal.TryParse(expression, out value); return value;}
If Sitecore.Context.Item.Fields("FieldName") IsNot Nothing Then MyProp = Sitecore.Context.Item.Fields("FieldName").ValueEnd If
public static TResult SafeGet<T, TResult>(this T o, Func<T, TResult> accessor) { return o == null ? null : accessor.Invoke(o);}
MyProp = Sitecore.Context.Items.Fields("FieldName").SafeGet(Function(x) x.Value)
// approach 7 (Added by Walt)c = 0;sw.Restart();foreach (int i in enumerable) if (i > 10) c++;sw.Stop();sw.ElapsedMilliseconds.Dump("Foreach loop. Total = " + c);
for (int col = 2; col < csv[i].Length; col += 2) { string outStart = csv[i][col]; string outEnd = csv[i][col + 1]; if (!string.IsNullOrEmpty(outStart) && !string.IsNullOrEmpty(outEnd)) { wtg.OutagePeriods.Add(new Period() { From = DateTime.Parse(outStart), To = DateTime.Parse(outEnd) }); } }
var outagePeriods = (from start in input from end in input select new ScheduledMaintenance(start,end)).Skip(2);
var timesInDay = from hour in Enumerable.Range(0, 24) from minute in Enumerable.Range(0, 4) select string.Format("{0:00}:{1:00}", hour, minute * 15));
// approach 8 (Added by Walt, Modified by Chris)c = 0;sw.Restart();foreach (int i in objectEnum) if (i > 10) c++;sw.Stop();sw.ElapsedMilliseconds.Dump("Foreach loop. Total = " + c);
List<string> fruits = new List<string>(); fruits.Add("apple"); fruits.Add("mango"); fruits.Add("grapes"); fruits.Add("oranges"); string CommaSeperated = string.Empty; foreach (string s in fruits) { CommaSeperated += "," + s; } CommaSeperated = CommaSeperated.Substring(1, CommaSeperated.Length-1); // With LINQ CommaSeperated = fruits.Aggregate((a, b) => a + "," + b);
public class Person { public string Name { get; set; } public int Age { get; set; }}
Console.WriteLine(Console.ReadLine().Split(' ').Select(t => int.Parse(t)).ToList().Max());
Console.WriteLine( Console.ReadLine() .Split(' ') .Select(t => int.Parse(t)) .ToList() .Max());
Console.WriteLine( Console.ReadLine() .Split(' ') .Select(int.Parse) .Max());
my linq experience usually looks like this:- write a long, complex linq query- test it, it doesn't work
else { temp += ", " + entry; }
else { entry += ", " + entry; }
byte[] uByteArray1 = Array.ConvertAll(sByteArray, x => (byte)x);
byte[] uByteArray1 = sByteArray.Cast<byte>().ToArray();
a@href@title, b, blockquote@cite, em, i, li, ol, pre, strike, strong, sub, super, u, ul
Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.