From 358821614360d9a191ae8dac1dcfc0f89971db4f Mon Sep 17 00:00:00 2001 From: leandromoh Date: Sat, 29 Oct 2016 16:47:52 -0200 Subject: [PATCH 01/15] countBy implemented --- MoreLinq/CountBy.cs | 79 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 MoreLinq/CountBy.cs diff --git a/MoreLinq/CountBy.cs b/MoreLinq/CountBy.cs new file mode 100644 index 000000000..47e48775b --- /dev/null +++ b/MoreLinq/CountBy.cs @@ -0,0 +1,79 @@ +#region License and Terms +// MoreLINQ - Extensions to LINQ to Objects +// Copyright (c) 2016 Leandro F. Vieira (leandromoh). All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace MoreLinq +{ + using System; + using System.Collections.Generic; + + static partial class MoreEnumerable + { + /// + /// Applies a key-generating function to each element of a sequence and returns a sequence of + /// unique keys and their number of occurrences in the original sequence. + /// + /// Type of the source sequence + /// Type of the projected element + /// Source sequence + /// Function that transforms each item of source sequence into a key to be compared against the others + /// A sequence of unique keys and their number of occurrences in the original sequence + public static IEnumerable> CountBy(this IEnumerable source, Func keySelector) + { + return source.CountBy(keySelector, null); + } + + /// + /// Applies a key-generating function to each element of a sequence and returns a sequence of + /// unique keys and their number of occurrences in the original sequence. + /// + /// Type of the source sequence + /// Type of the projected element + /// Source sequence + /// Function that transforms each item of source sequence into a key to be compared against the others + /// The equality comparer to use to determine whether or not keys are equal. + /// If null, the default equality comparer for TSource is used. + /// A sequence of unique keys and their number of occurrences in the original sequence + public static IEnumerable> CountBy(this IEnumerable source, Func keySelector, IEqualityComparer comparer) + { + if (source == null) throw new ArgumentNullException("source"); + if (keySelector == null) throw new ArgumentNullException("keySelector"); + + return CountByImpl(source, keySelector, comparer); + } + + private static IEnumerable> CountByImpl(IEnumerable source, Func keySelector, IEqualityComparer comparer) + { + var dic = new Dictionary(comparer); + + foreach (var item in source) + { + TKey key = keySelector(item); + + if (dic.ContainsKey(key)) + { + dic[key]++; + } + else + { + dic[key] = 1; + } + } + + return dic; + } + } +} From 987ef8c3c8b2576ada65799d94748497fb311fdf Mon Sep 17 00:00:00 2001 From: leandromoh Date: Sat, 29 Oct 2016 16:48:46 -0200 Subject: [PATCH 02/15] Tests implemented --- MoreLinq.Test/CountByTest.cs | 75 ++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 MoreLinq.Test/CountByTest.cs diff --git a/MoreLinq.Test/CountByTest.cs b/MoreLinq.Test/CountByTest.cs new file mode 100644 index 000000000..99cb89aef --- /dev/null +++ b/MoreLinq.Test/CountByTest.cs @@ -0,0 +1,75 @@ +#region License and Terms +// MoreLINQ - Extensions to LINQ to Objects +// Copyright (c) 2016 Leandro F. Vieira (leandromoh). All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using LinqEnumerable = System.Linq.Enumerable; + +namespace MoreLinq.Test +{ + [TestFixture] + public class CountByTest + { + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void CountByWithNullSequence() + { + IEnumerable sequence = null; + sequence.CountBy(x => x % 2 == 0); + } + + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void CountByWithNullProjection() + { + Func projection = null; + Enumerable.Range(1, 10).CountBy(projection); + } + + [Test] + public void CountBySimpleTest() + { + IEnumerable> result = new[] { 1, 2, 3, 4, 5, 6, 1, 2, 3, 1, 1, 2 }.CountBy(c => c); + + IEnumerable> expecteds = new Dictionary() { { 1, 4 }, { 2, 3 }, { 3, 2 }, { 4, 1 }, { 5, 1 }, { 6, 1 } }; + + result.AssertSequenceEqual(expecteds); + } + + [Test] + public void CountByEvenOddTest() + { + IEnumerable> result = Enumerable.Range(1, 100).CountBy(c => c % 2); + + IEnumerable> expecteds = new Dictionary() { { 1, 50 }, { 0, 50 } }; + + result.AssertSequenceEqual(expecteds); + } + + [Test] + public void CountByWithEqualityComparer() + { + IEnumerable> result = new[] { "a", "B", "c", "A", "b", "A" }.CountBy(c => c, StringComparer.OrdinalIgnoreCase); + + IEnumerable> expecteds = new Dictionary() { { "a", 3 }, { "B", 2 }, { "c", 1 } }; + + result.AssertSequenceEqual(expecteds); + } + } +} From 05265686758c3bc30ded87d893ef9e82dccc559d Mon Sep 17 00:00:00 2001 From: Leandro Fernandes Date: Tue, 1 Nov 2016 22:44:48 -0200 Subject: [PATCH 03/15] adjusts CountBy --- MoreLinq/CountBy.cs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/MoreLinq/CountBy.cs b/MoreLinq/CountBy.cs index 47e48775b..531029958 100644 --- a/MoreLinq/CountBy.cs +++ b/MoreLinq/CountBy.cs @@ -1,4 +1,4 @@ -#region License and Terms +#region License and Terms // MoreLINQ - Extensions to LINQ to Objects // Copyright (c) 2016 Leandro F. Vieira (leandromoh). All rights reserved. // @@ -19,6 +19,7 @@ namespace MoreLinq { using System; using System.Collections.Generic; + using System.Linq; static partial class MoreEnumerable { @@ -26,11 +27,11 @@ static partial class MoreEnumerable /// Applies a key-generating function to each element of a sequence and returns a sequence of /// unique keys and their number of occurrences in the original sequence. /// - /// Type of the source sequence - /// Type of the projected element - /// Source sequence - /// Function that transforms each item of source sequence into a key to be compared against the others - /// A sequence of unique keys and their number of occurrences in the original sequence + /// Type of the elements of the source sequence. + /// Type of the projected element. + /// Source sequence. + /// Function that transforms each item of source sequence into a key to be compared against the others. + /// A sequence of unique keys and their number of occurrences in the original sequence. public static IEnumerable> CountBy(this IEnumerable source, Func keySelector) { return source.CountBy(keySelector, null); @@ -39,14 +40,15 @@ public static IEnumerable> CountBy(this I /// /// Applies a key-generating function to each element of a sequence and returns a sequence of /// unique keys and their number of occurrences in the original sequence. + /// An additional argument specifies a comparer to use for testing equivalence of keys. /// - /// Type of the source sequence - /// Type of the projected element - /// Source sequence - /// Function that transforms each item of source sequence into a key to be compared against the others + /// Type of the elements of the source sequence. + /// Type of the projected element. + /// Source sequence. + /// Function that transforms each item of source sequence into a key to be compared against the others. /// The equality comparer to use to determine whether or not keys are equal. /// If null, the default equality comparer for TSource is used. - /// A sequence of unique keys and their number of occurrences in the original sequence + /// A sequence of unique keys and their number of occurrences in the original sequence. public static IEnumerable> CountBy(this IEnumerable source, Func keySelector, IEqualityComparer comparer) { if (source == null) throw new ArgumentNullException("source"); @@ -58,10 +60,11 @@ public static IEnumerable> CountBy(this I private static IEnumerable> CountByImpl(IEnumerable source, Func keySelector, IEqualityComparer comparer) { var dic = new Dictionary(comparer); + var keys = new List(); foreach (var item in source) { - TKey key = keySelector(item); + var key = keySelector(item); if (dic.ContainsKey(key)) { @@ -70,10 +73,11 @@ private static IEnumerable> CountByImpl(I else { dic[key] = 1; + keys.Add(key); } } - return dic; + return keys.Select(k => new KeyValuePair(k, dic[k])); } } } From 2da65a874a48dba79199833b27a7b2198794b1ab Mon Sep 17 00:00:00 2001 From: Leandro Fernandes Date: Tue, 1 Nov 2016 22:46:44 -0200 Subject: [PATCH 04/15] adjusts CountByTest --- MoreLinq.Test/CountByTest.cs | 37 ++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/MoreLinq.Test/CountByTest.cs b/MoreLinq.Test/CountByTest.cs index 99cb89aef..e7c2f78d9 100644 --- a/MoreLinq.Test/CountByTest.cs +++ b/MoreLinq.Test/CountByTest.cs @@ -1,4 +1,4 @@ -#region License and Terms +#region License and Terms // MoreLINQ - Extensions to LINQ to Objects // Copyright (c) 2016 Leandro F. Vieira (leandromoh). All rights reserved. // @@ -45,31 +45,48 @@ public void CountByWithNullProjection() [Test] public void CountBySimpleTest() { - IEnumerable> result = new[] { 1, 2, 3, 4, 5, 6, 1, 2, 3, 1, 1, 2 }.CountBy(c => c); + var result = new[] { 1, 2, 3, 4, 5, 6, 1, 2, 3, 1, 1, 2 }.CountBy(c => c); - IEnumerable> expecteds = new Dictionary() { { 1, 4 }, { 2, 3 }, { 3, 2 }, { 4, 1 }, { 5, 1 }, { 6, 1 } }; + var expectations = new List>() + { + { 1, 4 }, + { 2, 3 }, + { 3, 2 }, + { 4, 1 }, + { 5, 1 }, + { 6, 1 }, + }; - result.AssertSequenceEqual(expecteds); + result.AssertSequenceEqual(expectations); } [Test] public void CountByEvenOddTest() { - IEnumerable> result = Enumerable.Range(1, 100).CountBy(c => c % 2); + var result = Enumerable.Range(1, 100).CountBy(c => c % 2); - IEnumerable> expecteds = new Dictionary() { { 1, 50 }, { 0, 50 } }; + var expectations = new List>() + { + { 1, 50 }, + { 0, 50 }, + }; - result.AssertSequenceEqual(expecteds); + result.AssertSequenceEqual(expectations); } [Test] public void CountByWithEqualityComparer() { - IEnumerable> result = new[] { "a", "B", "c", "A", "b", "A" }.CountBy(c => c, StringComparer.OrdinalIgnoreCase); + var result = new[] { "a", "B", "c", "A", "b", "A" }.CountBy(c => c, StringComparer.OrdinalIgnoreCase); - IEnumerable> expecteds = new Dictionary() { { "a", 3 }, { "B", 2 }, { "c", 1 } }; + var expectations = new List>() + { + { "a", 3 }, + { "B", 2 }, + { "c", 1 }, + }; - result.AssertSequenceEqual(expecteds); + result.AssertSequenceEqual(expectations); } } } From db337ac2433f7679d4092a552d1e129d6f241f83 Mon Sep 17 00:00:00 2001 From: Leandro Fernandes Date: Tue, 1 Nov 2016 22:49:45 -0200 Subject: [PATCH 05/15] added List Add() extensions --- MoreLinq.Test/TestExtensions.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MoreLinq.Test/TestExtensions.cs b/MoreLinq.Test/TestExtensions.cs index 5e67b9587..0a7e47da8 100644 --- a/MoreLinq.Test/TestExtensions.cs +++ b/MoreLinq.Test/TestExtensions.cs @@ -73,5 +73,9 @@ internal static IEnumerable GenerateSplits(this string str, params char[ yield return split; } + internal static void Add(this List> list, TKey key, TValue value) + { + list.Add(new KeyValuePair(key, value)); + } } } From 4fadb743b402140e3b9abedcd833dbe061606480 Mon Sep 17 00:00:00 2001 From: Leandro Fernandes Date: Wed, 2 Nov 2016 11:21:41 -0200 Subject: [PATCH 06/15] added CountByHasKeysOrderedLikeGroupBy --- MoreLinq.Test/CountByTest.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MoreLinq.Test/CountByTest.cs b/MoreLinq.Test/CountByTest.cs index e7c2f78d9..0b0301550 100644 --- a/MoreLinq.Test/CountByTest.cs +++ b/MoreLinq.Test/CountByTest.cs @@ -88,5 +88,16 @@ public void CountByWithEqualityComparer() result.AssertSequenceEqual(expectations); } + + [Test] + public void CountByHasKeysOrderedLikeGroupBy() + { + var randomSequence = MoreEnumerable.Random(0, 100).Take(100).ToArray(); + + var countByKeys = randomSequence.CountBy(x => x).Select(x => x.Key); + var groupByKeys = randomSequence.GroupBy(x => x).Select(x => x.Key); + + countByKeys.AssertSequenceEqual(groupByKeys); + } } } From 6e218c890677147381a679ffef60745f18590bd3 Mon Sep 17 00:00:00 2001 From: Leandro Fernandes Date: Wed, 2 Nov 2016 11:24:38 -0200 Subject: [PATCH 07/15] changed List to IList --- MoreLinq.Test/TestExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MoreLinq.Test/TestExtensions.cs b/MoreLinq.Test/TestExtensions.cs index 0a7e47da8..319a4ca7b 100644 --- a/MoreLinq.Test/TestExtensions.cs +++ b/MoreLinq.Test/TestExtensions.cs @@ -73,7 +73,7 @@ internal static IEnumerable GenerateSplits(this string str, params char[ yield return split; } - internal static void Add(this List> list, TKey key, TValue value) + internal static void Add(this IList> list, TKey key, TValue value) { list.Add(new KeyValuePair(key, value)); } From 9bc8c951e3b20126011f2e457128888a43926619 Mon Sep 17 00:00:00 2001 From: Leandro Fernandes Date: Wed, 2 Nov 2016 16:51:54 -0200 Subject: [PATCH 08/15] adjust for become lazy --- MoreLinq/CountBy.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MoreLinq/CountBy.cs b/MoreLinq/CountBy.cs index 531029958..90790b605 100644 --- a/MoreLinq/CountBy.cs +++ b/MoreLinq/CountBy.cs @@ -77,7 +77,8 @@ private static IEnumerable> CountByImpl(I } } - return keys.Select(k => new KeyValuePair(k, dic[k])); + foreach (var key in keys) + yield return new KeyValuePair(key, dic[key]); } } } From 338941625b6197d64945f69416bab0f88b648ddf Mon Sep 17 00:00:00 2001 From: Leandro Fernandes Date: Wed, 2 Nov 2016 16:54:10 -0200 Subject: [PATCH 09/15] added CountByIsLazy --- MoreLinq.Test/CountByTest.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MoreLinq.Test/CountByTest.cs b/MoreLinq.Test/CountByTest.cs index 0b0301550..122419af6 100644 --- a/MoreLinq.Test/CountByTest.cs +++ b/MoreLinq.Test/CountByTest.cs @@ -99,5 +99,11 @@ public void CountByHasKeysOrderedLikeGroupBy() countByKeys.AssertSequenceEqual(groupByKeys); } + + [Test] + public void CountByIsLazy() + { + new BreakingSequence().CountBy(x => x.Length); + } } } From 74964a7e02b736814ae306d7e095527e4eb0af8d Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Wed, 2 Nov 2016 22:27:12 +0100 Subject: [PATCH 10/15] Optimization of lookups in CountBy --- MoreLinq/CountBy.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/MoreLinq/CountBy.cs b/MoreLinq/CountBy.cs index 90790b605..62f607a5d 100644 --- a/MoreLinq/CountBy.cs +++ b/MoreLinq/CountBy.cs @@ -61,24 +61,27 @@ private static IEnumerable> CountByImpl(I { var dic = new Dictionary(comparer); var keys = new List(); + var counts = new List(); foreach (var item in source) { var key = keySelector(item); - if (dic.ContainsKey(key)) + int i; + if (dic.TryGetValue(key, out i)) { - dic[key]++; + counts[i]++; } else { - dic[key] = 1; + dic[key] = keys.Count; keys.Add(key); + counts.Add(1); } } - foreach (var key in keys) - yield return new KeyValuePair(key, dic[key]); + for (var i = 0; i < keys.Count; i++) + yield return new KeyValuePair(keys[i], counts[i]); } } } From ae13491dbcef9126d81c53210ccfe537af1ccb41 Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Wed, 2 Nov 2016 22:27:57 +0100 Subject: [PATCH 11/15] Clear the keys dictionary in CountBy before yielding --- MoreLinq/CountBy.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/MoreLinq/CountBy.cs b/MoreLinq/CountBy.cs index 62f607a5d..ae6cf231f 100644 --- a/MoreLinq/CountBy.cs +++ b/MoreLinq/CountBy.cs @@ -20,6 +20,7 @@ namespace MoreLinq using System; using System.Collections.Generic; using System.Linq; + using System.Runtime.CompilerServices; static partial class MoreEnumerable { @@ -80,8 +81,26 @@ private static IEnumerable> CountByImpl(I } } + // The dictionary is no longer needed from this point forward so + // lose the reference and make it available as food for the GC. + // This optimization is designed to help cases where a slow running + // loop over the yielded pairs could span GC cycles. However, + // instead of doing simply the following: + // + // dic = null; + // + // the reference is nulled through a method that the JIT compiler + // is told not to try and inline; done so assuming that the above + // method could have been turned into a NOP (in theory). + + Null(ref dic); // dic = null; + for (var i = 0; i < keys.Count; i++) yield return new KeyValuePair(keys[i], counts[i]); } + + // ReSharper disable once RedundantAssignment + [MethodImpl(MethodImplOptions.NoInlining)] + static void Null(ref T obj) where T : class { obj = null; } } } From 01620492b8dab8b0765e51301c022ff69b14a013 Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Wed, 2 Nov 2016 22:31:56 +0100 Subject: [PATCH 12/15] Optimize CountBy for adjacent keys --- MoreLinq/CountBy.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/MoreLinq/CountBy.cs b/MoreLinq/CountBy.cs index ae6cf231f..2b4887521 100644 --- a/MoreLinq/CountBy.cs +++ b/MoreLinq/CountBy.cs @@ -63,15 +63,21 @@ private static IEnumerable> CountByImpl(I var dic = new Dictionary(comparer); var keys = new List(); var counts = new List(); + var havePrevKey = false; + var prevKey = default(TKey); + var index = 0; foreach (var item in source) { var key = keySelector(item); - int i; - if (dic.TryGetValue(key, out i)) + if (// key same as the previous? then re-use the index + (havePrevKey && dic.Comparer.GetHashCode(prevKey) == dic.Comparer.GetHashCode(key) + && dic.Comparer.Equals(prevKey, key)) + // otherwise try & find index of the key + || dic.TryGetValue(key, out index)) { - counts[i]++; + counts[index]++; } else { @@ -79,6 +85,9 @@ private static IEnumerable> CountByImpl(I keys.Add(key); counts.Add(1); } + + prevKey = key; + havePrevKey = true; } // The dictionary is no longer needed from this point forward so From 5e6808a52d2f3baf767cee192b37a1c9915d1dc3 Mon Sep 17 00:00:00 2001 From: Atif Aziz Date: Thu, 3 Nov 2016 17:02:21 +0100 Subject: [PATCH 13/15] Simpler CountBy iterator locals lifetime scoping --- MoreLinq/CountBy.cs | 57 ++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/MoreLinq/CountBy.cs b/MoreLinq/CountBy.cs index 2b4887521..b02407201 100644 --- a/MoreLinq/CountBy.cs +++ b/MoreLinq/CountBy.cs @@ -58,11 +58,37 @@ public static IEnumerable> CountBy(this I return CountByImpl(source, keySelector, comparer); } - private static IEnumerable> CountByImpl(IEnumerable source, Func keySelector, IEqualityComparer comparer) + static IEnumerable> CountByImpl( + IEnumerable source, Func keySelector, + IEqualityComparer comparer) + { + List keys; + List counts; + + // Avoid the temptation to inline the CountByLoop method, which + // exists solely to separate the scope & lifetimes of the locals + // needed for the actual looping of the source & production of the + // results (that happens once at the start of iteration) from + // those needed to simply yield the results. It is harder to reason + // about the lifetimes (if the code is inlined) with respect to how + // the compiler will rewrite the iterator code as a state machine. + // For background, see: + // http://blog.stephencleary.com/2010/02/q-should-i-set-variables-to-null-to.html + + CountByLoop(source, keySelector, comparer ?? EqualityComparer.Default, + out keys, out counts); + + for (var i = 0; i < keys.Count; i++) + yield return new KeyValuePair(keys[i], counts[i]); + } + + static void CountByLoop(IEnumerable source, + Func keySelector, IEqualityComparer comparer, + out List keys, out List counts) { var dic = new Dictionary(comparer); - var keys = new List(); - var counts = new List(); + keys = new List(); + counts = new List(); var havePrevKey = false; var prevKey = default(TKey); var index = 0; @@ -72,8 +98,8 @@ private static IEnumerable> CountByImpl(I var key = keySelector(item); if (// key same as the previous? then re-use the index - (havePrevKey && dic.Comparer.GetHashCode(prevKey) == dic.Comparer.GetHashCode(key) - && dic.Comparer.Equals(prevKey, key)) + (havePrevKey && comparer.GetHashCode(prevKey) == comparer.GetHashCode(key) + && comparer.Equals(prevKey, key)) // otherwise try & find index of the key || dic.TryGetValue(key, out index)) { @@ -89,27 +115,6 @@ private static IEnumerable> CountByImpl(I prevKey = key; havePrevKey = true; } - - // The dictionary is no longer needed from this point forward so - // lose the reference and make it available as food for the GC. - // This optimization is designed to help cases where a slow running - // loop over the yielded pairs could span GC cycles. However, - // instead of doing simply the following: - // - // dic = null; - // - // the reference is nulled through a method that the JIT compiler - // is told not to try and inline; done so assuming that the above - // method could have been turned into a NOP (in theory). - - Null(ref dic); // dic = null; - - for (var i = 0; i < keys.Count; i++) - yield return new KeyValuePair(keys[i], counts[i]); } - - // ReSharper disable once RedundantAssignment - [MethodImpl(MethodImplOptions.NoInlining)] - static void Null(ref T obj) where T : class { obj = null; } } } From 1e6b47ac91e17b0b4f2ede66bf3010306ff97f02 Mon Sep 17 00:00:00 2001 From: Leandro Fernandes Date: Tue, 8 Nov 2016 23:35:24 -0200 Subject: [PATCH 14/15] adjust on typeparamref --- MoreLinq/CountBy.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MoreLinq/CountBy.cs b/MoreLinq/CountBy.cs index b02407201..c9c715128 100644 --- a/MoreLinq/CountBy.cs +++ b/MoreLinq/CountBy.cs @@ -48,7 +48,7 @@ public static IEnumerable> CountBy(this I /// Source sequence. /// Function that transforms each item of source sequence into a key to be compared against the others. /// The equality comparer to use to determine whether or not keys are equal. - /// If null, the default equality comparer for TSource is used. + /// If null, the default equality comparer for is used. /// A sequence of unique keys and their number of occurrences in the original sequence. public static IEnumerable> CountBy(this IEnumerable source, Func keySelector, IEqualityComparer comparer) { From 203c5db61275d0e027bbea61f8929ac48887177d Mon Sep 17 00:00:00 2001 From: leandromoh Date: Thu, 10 Nov 2016 23:44:12 -0200 Subject: [PATCH 15/15] updated project.json and README.md --- MoreLinq/project.json | 4 ++-- README.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/MoreLinq/project.json b/MoreLinq/project.json index f78776ba7..4e0998d43 100644 --- a/MoreLinq/project.json +++ b/MoreLinq/project.json @@ -6,9 +6,9 @@ "authors": [ "MoreLINQ Developers." ], - "copyright": "\u00a9 2008 Jonathan Skeet. Portions \u00a9 2009 Atif Aziz, Chris Ammerman, Konrad Rudolph. Portions \u00a9 2010 Johannes Rudolph, Leopold Bushkin. Portions \u00a9 2015 Felipe Sateler, \u201csholland\u201d. Portions \u00a9 Microsoft. All rights reserved.", + "copyright": "\u00a9 2008 Jonathan Skeet. Portions \u00a9 2009 Atif Aziz, Chris Ammerman, Konrad Rudolph. Portions \u00a9 2010 Johannes Rudolph, Leopold Bushkin. Portions \u00a9 2015 Felipe Sateler, \u201csholland\u201d. Portions \u00a9 2016 Leandro F. Vieira (leandromoh). Portions \u00a9 Microsoft. All rights reserved.", "packOptions": { - "releaseNotes": "Adds new operators: Assert, AtLeast, Cartesian, EndsWith, EquiZip, Exclude, FallbackIfEmpty, FullGroupJoin, GroupAdjacent, Incremental, Interleave, Lag, Lead, NestedLoops, OrderBy, PartialSort, PartialSortBy, Partition, Permutations, Random, RandomDouble, RandomSubset, Rank, RankBy, Repeat, RunLengthEncode, Segment, Slice, SortedMerge, StartsWith, Subsets, TagFirstLast, ThenBy, TraverseBreadthFirst, TraverseDepthFirst, Windowed, ZipShortest. See also https://github.com/morelinq/MoreLINQ/wiki/API-Changes.", + "releaseNotes": "Adds new operators: Assert, AtLeast, Cartesian, CountBy, EndsWith, EquiZip, Exclude, FallbackIfEmpty, FullGroupJoin, GroupAdjacent, Incremental, Interleave, Lag, Lead, NestedLoops, OrderBy, PartialSort, PartialSortBy, Partition, Permutations, Random, RandomDouble, RandomSubset, Rank, RankBy, Repeat, RunLengthEncode, Segment, Slice, SortedMerge, StartsWith, Subsets, TagFirstLast, ThenBy, TraverseBreadthFirst, TraverseDepthFirst, Windowed, ZipShortest. See also https://github.com/morelinq/MoreLINQ/wiki/API-Changes.", "summary": "This project enhances LINQ to Objects with extra methods, in a manner which keeps to the spirit of LINQ.", "owners": [ "Jon Skeet", diff --git a/README.md b/README.md index 3adbc12de..aad7ab85f 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Operator | Summary `Cartesian` | Returns the Cartesian product of two sequences by combining each element of the first set with each in the second and applying the user=define projection to the pair `Concat` | Returns a sequence consisting of the head element and the given tail elements. This method has 2 overloads. `Consume` | Completely consumes the given sequence. This method uses immediate execution, and doesn't store any data during execution +`CountBy` | Applies a key-generating function to each element of a sequence and returns a sequence of unique keys and their number of occurrences in the original sequence. This method has 2 overloads. `DistinctBy` | Returns all distinct elements of the given source, where "distinctness" is determined via a projection and the default equality comparer for the projected type. This method has 2 overloads. `EquiZip` | Returns a projection of tuples, where each tuple contains the N-th element from each of the argument sequences. This method has 3 overloads. `ExceptBy` | Returns the set of elements in the first sequence which aren't in the second sequence, according to a given key selector. This method has 2 overloads.