Skip to content

Commit

Permalink
Add IndexBy
Browse files Browse the repository at this point in the history
This is a squashed merge of PR #562 that closes #560.
  • Loading branch information
leandromoh authored and atifaziz committed Jul 17, 2019
1 parent 531fe71 commit 5205ea2
Show file tree
Hide file tree
Showing 4 changed files with 263 additions and 0 deletions.
123 changes: 123 additions & 0 deletions MoreLinq.Test/IndexByTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#region License and Terms
// MoreLINQ - Extensions to LINQ to Objects
// Copyright (c) 2019 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.Test
{
using System;
using NUnit.Framework;

[TestFixture]
public class IndexByTest
{
[Test]
public void IndexBySimpleTest()
{
var source = new[] { "ana", "beatriz", "carla", "bob", "davi", "adriano", "angelo", "carlos" };
var result = source.IndexBy(x => x.First());

result.AssertSequenceEqual(
KeyValuePair.Create(0, "ana" ),
KeyValuePair.Create(0, "beatriz"),
KeyValuePair.Create(0, "carla" ),
KeyValuePair.Create(1, "bob" ),
KeyValuePair.Create(0, "davi" ),
KeyValuePair.Create(1, "adriano"),
KeyValuePair.Create(2, "angelo" ),
KeyValuePair.Create(1, "carlos" ));
}

[Test]
public void IndexByWithSecondOccurenceImmediatelyAfterFirst()
{
var result = "jaffer".IndexBy(c => c);

result.AssertSequenceEqual(
KeyValuePair.Create(0, 'j'),
KeyValuePair.Create(0, 'a'),
KeyValuePair.Create(0, 'f'),
KeyValuePair.Create(1, 'f'),
KeyValuePair.Create(0, 'e'),
KeyValuePair.Create(0, 'r'));
}

[Test]
public void IndexByWithEqualityComparer()
{
var source = new[] { "a", "B", "c", "A", "b", "A" };
var result = source.IndexBy(c => c, StringComparer.OrdinalIgnoreCase);

result.AssertSequenceEqual(
KeyValuePair.Create(0, "a"),
KeyValuePair.Create(0, "B"),
KeyValuePair.Create(0, "c"),
KeyValuePair.Create(1, "A"),
KeyValuePair.Create(1, "b"),
KeyValuePair.Create(2, "A"));
}

[Test]
public void IndexByIsLazy()
{
new BreakingSequence<string>().IndexBy(BreakingFunc.Of<string, char>());
}

[Test]
public void IndexByWithSomeNullKeys()
{
var source = new[] { "foo", null, "bar", "baz", null, null, "baz", "bar", null, "foo" };
var result = source.IndexBy(c => c);

const string @null = null; // type inference happiness
result.AssertSequenceEqual(
KeyValuePair.Create(0, "foo"),
KeyValuePair.Create(0, @null),
KeyValuePair.Create(0, "bar"),
KeyValuePair.Create(0, "baz"),
KeyValuePair.Create(1, @null),
KeyValuePair.Create(2, @null),
KeyValuePair.Create(1, "baz"),
KeyValuePair.Create(1, "bar"),
KeyValuePair.Create(3, @null),
KeyValuePair.Create(1, "foo"));
}

[Test]
public void IndexBytDoesNotIterateUnnecessaryElements()
{
var source = MoreEnumerable.From(() => "ana",
() => "beatriz",
() => "carla",
() => "bob",
() => "davi",
() => throw new TestException(),
() => "angelo",
() => "carlos");

var result = source.IndexBy(x => x.First());

result.Take(5).AssertSequenceEqual(
KeyValuePair.Create(0, "ana" ),
KeyValuePair.Create(0, "beatriz"),
KeyValuePair.Create(0, "carla" ),
KeyValuePair.Create(1, "bob" ),
KeyValuePair.Create(0, "davi" ));

Assert.Throws<TestException>(() =>
result.ElementAt(5));
}
}
}
54 changes: 54 additions & 0 deletions MoreLinq/Extensions.g.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2847,6 +2847,60 @@ public static IEnumerable<KeyValuePair<int, TSource>> Index<TSource>(this IEnume

}

/// <summary><c>IndexBy</c> extension.</summary>

[GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")]
public static partial class IndexByExtension
{
/// <summary>
/// Applies a key-generating function to each element of a sequence and
/// returns a sequence that contains the elements of the original
/// sequence as well its key and index inside the group of its key.
/// </summary>
/// <typeparam name="TSource">Type of the source sequence elements.</typeparam>
/// <typeparam name="TKey">Type of the projected key.</typeparam>
/// <param name="source">Source sequence.</param>
/// <param name="keySelector">
/// Function that projects the key given an element in the source sequence.</param>
/// <returns>
/// A sequence of elements paired with their index within the key-group.
/// The index is the key and the element is the value of the pair.
/// </returns>

public static IEnumerable<KeyValuePair<int, TSource>>
IndexBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector) => MoreEnumerable. IndexBy(source, keySelector);

/// <summary>
/// Applies a key-generating function to each element of a sequence and
/// returns a sequence that contains the elements of the original
/// sequence as well its key and index inside the group of its key.
/// An additional parameter specifies a comparer to use for testing the
/// equivalence of keys.
/// </summary>
/// <typeparam name="TSource">Type of the source sequence elements.</typeparam>
/// <typeparam name="TKey">Type of the projected key.</typeparam>
/// <param name="source">Source sequence.</param>
/// <param name="keySelector">
/// Function that projects the key given an element in the source sequence.</param>
/// <param name="comparer">
/// The equality comparer to use to determine whether or not keys are
/// equal. If <c>null</c>, the default equality comparer for
/// <typeparamref name="TSource"/> is used.</param>
/// <returns>
/// A sequence of elements paired with their index within the key-group.
/// The index is the key and the element is the value of the pair.
/// </returns>

public static IEnumerable<KeyValuePair<int, TSource>>
IndexBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
IEqualityComparer<TKey> comparer) => MoreEnumerable. IndexBy(source, keySelector, comparer);

}

/// <summary><c>Insert</c> extension.</summary>

[GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")]
Expand Down
76 changes: 76 additions & 0 deletions MoreLinq/IndexBy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#region License and Terms
// MoreLINQ - Extensions to LINQ to Objects
// Copyright (c) 2019 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;
using System.Linq;

static partial class MoreEnumerable
{
/// <summary>
/// Applies a key-generating function to each element of a sequence and
/// returns a sequence that contains the elements of the original
/// sequence as well its key and index inside the group of its key.
/// </summary>
/// <typeparam name="TSource">Type of the source sequence elements.</typeparam>
/// <typeparam name="TKey">Type of the projected key.</typeparam>
/// <param name="source">Source sequence.</param>
/// <param name="keySelector">
/// Function that projects the key given an element in the source sequence.</param>
/// <returns>
/// A sequence of elements paired with their index within the key-group.
/// The index is the key and the element is the value of the pair.
/// </returns>

public static IEnumerable<KeyValuePair<int, TSource>>
IndexBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector) =>
source.IndexBy(keySelector, null);

/// <summary>
/// Applies a key-generating function to each element of a sequence and
/// returns a sequence that contains the elements of the original
/// sequence as well its key and index inside the group of its key.
/// An additional parameter specifies a comparer to use for testing the
/// equivalence of keys.
/// </summary>
/// <typeparam name="TSource">Type of the source sequence elements.</typeparam>
/// <typeparam name="TKey">Type of the projected key.</typeparam>
/// <param name="source">Source sequence.</param>
/// <param name="keySelector">
/// Function that projects the key given an element in the source sequence.</param>
/// <param name="comparer">
/// The equality comparer to use to determine whether or not keys are
/// equal. If <c>null</c>, the default equality comparer for
/// <typeparamref name="TSource"/> is used.</param>
/// <returns>
/// A sequence of elements paired with their index within the key-group.
/// The index is the key and the element is the value of the pair.
/// </returns>

public static IEnumerable<KeyValuePair<int, TSource>>
IndexBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
IEqualityComparer<TKey> comparer) =>
from e in source.ScanBy(keySelector, k => (Index: -1, Item: default(TSource)), (s, k, e) => (s.Index + 1, e), comparer)
select new KeyValuePair<int, TSource>(e.Value.Index, e.Value.Item);
}
}
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,16 @@ the source sequence.

This method has 2 overloads.

### IndexBy


Applies a key-generating function to each element of a sequence and returns
a sequence that contains the elements of the original sequence as well its
key and index inside the group of its key. An additional argument specifies
a comparer to use for testing equivalence of keys.

This method has 2 overloads.

### Insert

Inserts the elements of a sequence into another sequence at a specified index.
Expand Down

0 comments on commit 5205ea2

Please sign in to comment.