forked from morelinq/MoreLINQ
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
220 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
#region License and Terms | ||
// MoreLINQ - Extensions to LINQ to Objects | ||
// Copyright (c) 2015 Jonathan Skeet. 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 System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using NUnit.Framework; | ||
|
||
|
||
namespace MoreLinq.Test | ||
{ | ||
[TestFixture] | ||
public class FullGroupJoinTest | ||
{ | ||
[Test] | ||
[ExpectedException(typeof(ArgumentNullException))] | ||
public void FullGroupFirstNull() | ||
{ | ||
((IEnumerable<string>)null).FullGroupJoin(Enumerable.Empty<string>(), x => x, x => x, DummySelector); | ||
} | ||
|
||
[Test] | ||
[ExpectedException(typeof(ArgumentNullException))] | ||
public void FullGroupSecondNull() | ||
{ | ||
Enumerable.Empty<string>().FullGroupJoin((IEnumerable<string>)null, x => x, x => x, DummySelector); | ||
} | ||
|
||
[Test] | ||
[ExpectedException(typeof(ArgumentNullException))] | ||
public void FullGroupFirstKeyNull() | ||
{ | ||
Enumerable.Empty<string>().FullGroupJoin(Enumerable.Empty<string>(), (Func<string, string>)null, x => x, DummySelector); | ||
} | ||
|
||
[Test] | ||
[ExpectedException(typeof(ArgumentNullException))] | ||
public void FullGroupSecondKeyNull() | ||
{ | ||
Enumerable.Empty<string>().FullGroupJoin(Enumerable.Empty<string>(), x => x, (Func<string, string>)null, DummySelector); | ||
} | ||
|
||
[Test] | ||
[ExpectedException(typeof(ArgumentNullException))] | ||
public void FullGroupResultSelectorNull() | ||
{ | ||
Enumerable.Empty<string>().FullGroupJoin(Enumerable.Empty<string>(), x => x, x => x, (Func<string, IEnumerable<string>, IEnumerable<string>, string>)null); | ||
} | ||
|
||
[Test] | ||
public void FullGroupIsLazy() | ||
{ | ||
var listA = new BreakingSequence<int>(); | ||
var listB = new BreakingSequence<int>(); | ||
|
||
listA.FullGroupJoin(listB, x => x, x => x, DummySelector); | ||
Assert.True(true); | ||
} | ||
|
||
[Test] | ||
public void FullGroupJoinsResults() | ||
{ | ||
var listA = new[] { 1, 2 }; | ||
var listB = new[] { 2, 3 }; | ||
|
||
var result = listA.FullGroupJoin(listB, x => x, x => x, (key, first, second) => new { key, first, second }).ToDictionary(a => a.key); | ||
|
||
Assert.AreEqual(3, result.Keys.Count); | ||
|
||
Assert.IsEmpty(result[1].second); | ||
Assert.AreEqual(1, result[1].first.Single()); | ||
|
||
Assert.IsEmpty(result[3].first); | ||
Assert.AreEqual(3, result[3].second.Single()); | ||
|
||
Assert.IsNotEmpty(result[2].first); | ||
Assert.AreEqual(2, result[2].first.Single()); | ||
Assert.IsNotEmpty(result[2].second); | ||
Assert.AreEqual(2, result[2].second.Single()); | ||
} | ||
|
||
private static T1 DummySelector<T1, T2, T3>(T1 t1, T2 t2, T3 t3) | ||
{ | ||
return t1; | ||
} | ||
} | ||
} | ||
|
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
#region License and Terms | ||
// MoreLINQ - Extensions to LINQ to Objects | ||
// Copyright (c) 2008 Jonathan Skeet. 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; | ||
using System.Linq; | ||
using System.Text; | ||
This comment has been minimized.
Sorry, something went wrong. |
||
|
||
// Inspiration & credit: http://stackoverflow.com/a/13503860/6682 | ||
static partial class MoreEnumerable | ||
{ | ||
/// <summary> | ||
/// Performs a Full Group Join between the <paramref name="first"/> and <paramref name="second"/> sequences. | ||
/// </summary> | ||
/// <remarks> | ||
/// This operator uses deferred execution and streams the results. | ||
/// </remarks> | ||
/// <typeparam name="TFirst">The type of the elements in the first input sequence</typeparam> | ||
/// <typeparam name="TSecond">The type of the elements in the first input sequence</typeparam> | ||
/// <typeparam name="TKey">The type of the key to use to join</typeparam> | ||
/// <typeparam name="TResult">The type of the elements of the resulting sequence</typeparam> | ||
/// <param name="first">First sequence</param> | ||
/// <param name="second">Second secuence</param> | ||
/// <param name="firstKeySelector">The mapping from first sequence to key</param> | ||
/// <param name="secondKeySelector">The mapping from second sequence to key</param> | ||
/// <param name="resultSelector">Function to apply to each pair of elements plus the key</param> | ||
/// <returns>A sequence of elements joined from <paramref name="first"/> and <paramref name="second"/>. | ||
/// </returns> | ||
public static IEnumerable<TResult> FullGroupJoin<TFirst, TSecond, TKey, TResult>(this IEnumerable<TFirst> first, | ||
IEnumerable<TSecond> second, | ||
Func<TFirst, TKey> firstKeySelector, | ||
Func<TSecond, TKey> secondKeySelector, | ||
Func<TKey, IEnumerable<TFirst>, IEnumerable<TSecond>, TResult> resultSelector) | ||
{ | ||
return FullGroupJoin(first, second, firstKeySelector, secondKeySelector, resultSelector, EqualityComparer<TKey>.Default); | ||
} | ||
|
||
/// <summary> | ||
/// Performs a Full Group Join between the <paramref name="first"/> and <paramref name="second"/> sequences. | ||
/// </summary> | ||
/// <remarks> | ||
/// This operator uses deferred execution and streams the results. | ||
/// </remarks> | ||
/// <typeparam name="TFirst">The type of the elements in the first input sequence</typeparam> | ||
/// <typeparam name="TSecond">The type of the elements in the first input sequence</typeparam> | ||
/// <typeparam name="TKey">The type of the key to use to join</typeparam> | ||
/// <typeparam name="TResult">The type of the elements of the resulting sequence</typeparam> | ||
/// <param name="first">First sequence</param> | ||
/// <param name="second">Second secuence</param> | ||
/// <param name="firstKeySelector">The mapping from first sequence to key</param> | ||
/// <param name="secondKeySelector">The mapping from second sequence to key</param> | ||
/// <param name="resultSelector">Function to apply to each pair of elements plus the key</param> | ||
/// <param name="comparer">The equality comparer to use to determine whether or not keys are equal. | ||
/// If null, the default equality comparer for <c>TKey</c> is used.</param> | ||
/// <returns>A sequence of elements joined from <paramref name="first"/> and <paramref name="second"/>. | ||
/// </returns> | ||
public static IEnumerable<TResult> FullGroupJoin<TFirst, TSecond, TKey, TResult>(this IEnumerable<TFirst> first, | ||
IEnumerable<TSecond> second, | ||
Func<TFirst, TKey> firstKeySelector, | ||
Func<TSecond, TKey> secondKeySelector, | ||
Func<TKey, IEnumerable<TFirst>, IEnumerable<TSecond>, TResult> resultSelector, | ||
IEqualityComparer<TKey> comparer) | ||
{ | ||
if (first == null) throw new ArgumentNullException("first"); | ||
if (second == null) throw new ArgumentNullException("second"); | ||
if (firstKeySelector == null) throw new ArgumentNullException("firstKeySelector"); | ||
if (secondKeySelector == null) throw new ArgumentNullException("secondKeySelector"); | ||
if (resultSelector == null) throw new ArgumentNullException("resultSelector"); | ||
|
||
return FullGroupJoinImpl(first, second, firstKeySelector, secondKeySelector, resultSelector, comparer); | ||
} | ||
|
||
private static IEnumerable<TResult> FullGroupJoinImpl<TFirst, TSecond, TKey, TResult>(IEnumerable<TFirst> first, | ||
IEnumerable<TSecond> second, | ||
Func<TFirst, TKey> firstKeySelector, | ||
Func<TSecond, TKey> secondKeySelector, | ||
Func<TKey, IEnumerable<TFirst>, IEnumerable<TSecond>, TResult> resultSelector, | ||
IEqualityComparer<TKey> comparer) | ||
{ | ||
comparer = comparer ?? EqualityComparer<TKey>.Default; | ||
|
||
var alookup = first.ToLookup(firstKeySelector, comparer); | ||
var blookup = second.ToLookup(secondKeySelector, comparer); | ||
var keys = alookup.Select(p => p.Key).Union(blookup.Select(p => p.Key), comparer); | ||
|
||
var join = keys.Select(key => resultSelector(key, alookup[key], blookup[key])); | ||
|
||
// We do the iteration + yield return to delay executing the earlier ToLookup | ||
// until the result is enumerated | ||
foreach (var item in join) { | ||
yield return item; | ||
} | ||
} | ||
} | ||
} |
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
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
System.Text
import is unused inFullGroupJoin.cs