Created
October 28, 2016 03:33
-
-
Save ufcpp/2b3e1a5821169f6b21ded175ad05c752 to your computer and use it in GitHub Desktop.
index付きforeach
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
namespace A | |
{ | |
// IReadOnlyList 専用、アロケーション発生しない実装 | |
public static partial class TupleEnumerable | |
{ | |
public struct IndexedListEnumerable<T> : IEnumerable<(T item, int index)> | |
{ | |
private IReadOnlyList<T> _list; | |
public IndexedListEnumerable(IReadOnlyList<T> list) { _list = list; } | |
public IndexedListEnumerator<T> GetEnumerator() => new IndexedListEnumerator<T>(_list); | |
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |
IEnumerator<(T item, int index)> IEnumerable<(T item, int index)>.GetEnumerator() => GetEnumerator(); | |
} | |
public struct IndexedListEnumerator<T> : IEnumerator<(T item, int index)> | |
{ | |
public (T item, int index) Current => (_list[_i], _i); | |
int _i; | |
IReadOnlyList<T> _list; | |
internal IndexedListEnumerator(IReadOnlyList<T> list) | |
{ | |
_i = -1; | |
_list = list; | |
} | |
public bool MoveNext() | |
{ | |
_i++; | |
return _i < _list.Count; | |
} | |
object IEnumerator.Current => Current; | |
public void Dispose() { } | |
public void Reset() { throw new NotImplementedException(); } | |
} | |
public static IndexedListEnumerable<T> Indexed<T>(this IReadOnlyList<T> source) | |
{ | |
if (source == null) throw new ArgumentNullException(nameof(source)); | |
return new IndexedListEnumerable<T>(source); | |
} | |
} | |
} |
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
namespace B | |
{ | |
// 汎用実装。GetEnumeratorでbox化避けれない。 | |
public static partial class TupleEnumerable | |
{ | |
public struct IndexedEnumerable<T> : IEnumerable<(T item, int index)> | |
{ | |
private IEnumerable<T> _e; | |
public IndexedEnumerable(IEnumerable<T> e) { _e = e; } | |
public IndexedEnumerator<T> GetEnumerator() => new IndexedEnumerator<T>(_e.GetEnumerator()); | |
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |
IEnumerator<(T item, int index)> IEnumerable<(T item, int index)>.GetEnumerator() => GetEnumerator(); | |
} | |
public struct IndexedEnumerator<T> : IEnumerator<(T item, int index)> | |
{ | |
public (T item, int index) Current => (_e.Current, _i); | |
int _i; | |
IEnumerator<T> _e; | |
internal IndexedEnumerator(IEnumerator<T> e) | |
{ | |
_i = -1; | |
_e = e; | |
} | |
public bool MoveNext() | |
{ | |
_i++; | |
return _e.MoveNext(); | |
} | |
object IEnumerator.Current => Current; | |
public void Dispose() { } | |
public void Reset() { throw new NotImplementedException(); } | |
} | |
public static IndexedEnumerable<T> Indexed<T>(this IEnumerable<T> source) | |
{ | |
if (source == null) throw new ArgumentNullException(nameof(source)); | |
return new IndexedEnumerable<T>(source); | |
} | |
} | |
} |
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
namespace C | |
{ | |
// イテレーターを使った実装。シンプルだけど、どうしてもヒープ使っちゃう。 | |
public static partial class TupleEnumerable | |
{ | |
public static IEnumerable<(T item, int index)> Indexed<T>(this IEnumerable<T> source) | |
{ | |
if (source == null) throw new ArgumentNullException(nameof(source)); | |
IEnumerable<(T item, int index)> impl() | |
{ | |
var i = 0; | |
foreach (var item in source) | |
{ | |
yield return (item, i); | |
++i; | |
} | |
} | |
return impl(); | |
} | |
} | |
} |
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 切り替えで、どの Indexed が呼ばれるかを切り替え | |
// 手元の環境だと以下の通り(GetTotalMemory の前後差分0が理想) | |
// A: 0 | |
// B: 237568 | |
// C: 720896 | |
using A; | |
class Program | |
{ | |
static void Main() | |
{ | |
var items = new List<int> { 2, 3, 5, 7, 11, 13, 17 }; | |
items.Indexed(); | |
var begin = GC.GetTotalMemory(false); | |
for (int i = 0; i < 10000; i++) | |
{ | |
var sum = 0; | |
foreach (var (item, index) in items.Indexed()) | |
{ | |
sum += item * index; | |
} | |
} | |
var end = GC.GetTotalMemory(false); | |
Console.WriteLine(end - begin); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment