Last active
July 16, 2016 08:26
-
-
Save ig-sinicyn/7dfe2413f88ee19244dbabf213e8119b to your computer and use it in GitHub Desktop.
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
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Linq; | |
using CodeJam.Arithmetic; | |
using CodeJam.Collections; | |
using CodeJam.PerfTests; | |
using JetBrains.Annotations; | |
using NUnit.Framework; | |
using static CodeJam.AssemblyWideConfig; | |
using static CodeJam.PerfTests.CompetitionHelpers; | |
// ReSharper disable once CheckNamespace | |
namespace CodeJam | |
{ | |
#region Helpers | |
public static class Ext | |
{ | |
public static T MyMinBy<T, TValue>(this IEnumerable<T> source, Func<T, TValue> selector) | |
{ | |
var greater = Operators<TValue>.GreaterThan; | |
var result = default(T); | |
var nullResult = default(T); | |
var resultValue = default(TValue); | |
bool hasData = false; | |
foreach (var item in source) | |
{ | |
var temp = selector(item); | |
if (temp == null) | |
{ | |
nullResult = item; | |
hasData = true; | |
} | |
else if (!hasData || greater(resultValue, temp)) | |
{ | |
result = item; | |
resultValue = temp; | |
hasData = true; | |
} | |
} | |
if (!hasData && result == null) | |
throw new Exception("Bla-bla-bla"); | |
return result == null ? nullResult : result; | |
} | |
public static T MyMinByComparer<T, TValue>( | |
this IEnumerable<T> source, | |
Func<T, TValue> selector, | |
IComparer<TValue> comparer = null) | |
{ | |
comparer = comparer ?? Comparer<TValue>.Default; | |
var result = default(T); | |
var nullResult = default(T); | |
var resultValue = default(TValue); | |
bool hasData = false; | |
foreach (var item in source) | |
{ | |
var temp = selector(item); | |
if (temp == null) | |
{ | |
nullResult = item; | |
hasData = true; | |
} | |
else if (!hasData || comparer.Compare(resultValue, temp) > 0) | |
{ | |
result = item; | |
resultValue = temp; | |
hasData = true; | |
} | |
} | |
if (!hasData && result == null) | |
throw new Exception("Bla-bla-bla"); | |
return result == null ? nullResult : result; | |
} | |
} | |
#endregion | |
[PublicAPI] | |
[TestFixture(Category = PerfTestCategory + ": EnumHelper")] | |
public class TempPerfTests | |
{ | |
public class Data | |
{ | |
public Data(int structField) | |
{ | |
StructField = structField; | |
StructFieldNullable = (structField % 10) == 0 | |
? (int?)null | |
: structField; | |
StringField = (structField % 10) == 0 | |
? null | |
: structField.ToString(); | |
} | |
public int StructField { get; } | |
public int? StructFieldNullable { get; } | |
public string StringField { get; } | |
} | |
private static readonly Data[] _data = GetData(); | |
private static Data[] GetData() | |
{ | |
var rnd = new Random(0); // fixed seed to get repeatable results; | |
return Enumerable.Range(1, 1000).Select(i => new Data(rnd.Next(1000))).ToArray(); | |
} | |
[Test] | |
public void CheckCorrectness() | |
{ | |
var x1 = _data.MinBy(a => a.StructField); | |
var x2 = _data.MyMinBy(a => a.StructField); | |
var x3 = _data.MyMinByComparer(a => a.StructField); | |
var x4 = _data.Select(a => a.StructField).Min(); | |
Assert.AreEqual(x1, x2); | |
Assert.AreEqual(x1, x3); | |
Assert.AreEqual(x1.StructField, x4); | |
var x21 = _data.MinBy(a => a.StructFieldNullable); | |
var x22 = _data.MyMinBy(a => a.StructFieldNullable); | |
var x23 = _data.MyMinByComparer(a => a.StructFieldNullable); | |
var x24 = _data.Select(a => a.StructFieldNullable).Min(); | |
Assert.AreEqual(x21, x22); | |
Assert.AreEqual(x21, x23); | |
Assert.AreEqual(x21.StructFieldNullable, x24); | |
var x31 = _data.MinBy(a => a.StringField); | |
var x32 = _data.MyMinBy(a => a.StringField); | |
var x33 = _data.MyMinByComparer(a => a.StringField); | |
var x34 = _data.Select(a => a.StringField).Min(); | |
Assert.AreEqual(x31, x32); | |
Assert.AreEqual(x31, x33); | |
Assert.AreEqual(x31.StringField, x34); | |
} | |
[Test] | |
public void RunMinByIntCase() => Competition.Run<MinByIntCase>(RunConfig); | |
public class MinByIntCase | |
{ | |
[CompetitionBaseline] | |
public Data MinCodeJam() => _data.MinBy(x => x.StructField); | |
[CompetitionBenchmark(18.45, 19.60)] | |
public Data MinNaive() => _data.OrderBy(x => x.StructField).FirstOrDefault(); | |
[CompetitionBenchmark(1.18, 1.33)] | |
public Data MyMinBy() => _data.MyMinBy(x => x.StructField); | |
[CompetitionBenchmark(1.35, 1.40)] | |
public Data MyMinByComparer() => _data.MyMinByComparer(x => x.StructField); | |
[CompetitionBenchmark(0.12, 0.14)] | |
public Data MinDoneRight() | |
{ | |
Data result = null; | |
int resultValue = 0; | |
var local = _data; | |
foreach (var other in local) | |
{ | |
if (result == null || resultValue > other.StructField) | |
{ | |
result = other; | |
resultValue = other.StructField; | |
} | |
} | |
return result; | |
} | |
} | |
[Test] | |
public void RunMinByStringCase() => Competition.Run<MinByStringCase>(RunConfig); | |
public class MinByStringCase | |
{ | |
[CompetitionBaseline] | |
public Data MinCodeJam() => _data.MinBy(x => x.StringField); | |
[CompetitionBenchmark(13.20, 14.34)] | |
public Data MinNaive() => _data.OrderBy(x => x.StringField).FirstOrDefault(); | |
[CompetitionBenchmark(0.10, 0.11)] | |
public Data MyMinBy() => _data.MyMinBy(x => x.StringField); | |
[CompetitionBenchmark(0.89, 0.97)] | |
public Data MyMinByComparer() => _data.MyMinByComparer(x => x.StringField); | |
[CompetitionBenchmark(0.81, 0.87)] | |
public Data MinDoneRight() | |
{ | |
Data result = null; | |
Data nullResult = null; | |
string resultValue = null; | |
var local = _data; | |
foreach (var other in local) | |
{ | |
if (other.StringField == null) | |
{ | |
nullResult = other; | |
} | |
else if (result == null || string.Compare(resultValue, other.StringField) > 0) | |
{ | |
result = other; | |
resultValue = other.StringField; | |
} | |
} | |
return result ?? nullResult; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment