-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathIEnumerableExtensions.cs
More file actions
146 lines (134 loc) · 4.81 KB
/
Copy pathIEnumerableExtensions.cs
File metadata and controls
146 lines (134 loc) · 4.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
using System;
using System.Collections.Generic;
using System.Linq;
namespace Semmle.Util
{
public static class IEnumerableExtensions
{
/// <summary>
/// Find the first element in the sequence, or null if the sequence is empty.
/// </summary>
/// <typeparam name="T">The type of the sequence.</typeparam>
/// <param name="list">The list of items.</param>
/// <returns>The first item, or null if the sequence is empty.</returns>
public static T? FirstOrNull<T>(this IEnumerable<T> list) where T : struct
{
return list.Any() ? (T?)list.First() : null;
}
/// <summary>
/// Finds the last element a sequence, or null if the sequence is empty.
/// </summary>
/// <typeparam name="T">The type of the elements in the sequence.</typeparam>
/// <param name="list">The list of items.</param>
/// <returns>The last item, or null if the sequence is empty.</returns>
public static T? LastOrNull<T>(this IEnumerable<T> list) where T : struct
{
return list.Any() ? (T?)list.Last() : null;
}
/// <summary>
/// Interleaves the elements from the two sequences.
/// </summary>
public static IEnumerable<T> Interleave<T>(this IEnumerable<T> first, IEnumerable<T> second)
{
using var enumerator1 = first.GetEnumerator();
using var enumerator2 = second.GetEnumerator();
bool moveNext1;
while ((moveNext1 = enumerator1.MoveNext()) && enumerator2.MoveNext())
{
yield return enumerator1.Current;
yield return enumerator2.Current;
}
if (moveNext1)
{
// `first` has more elements than `second`
yield return enumerator1.Current;
while (enumerator1.MoveNext())
{
yield return enumerator1.Current;
}
}
while (enumerator2.MoveNext())
{
// `second` has more elements than `first`
yield return enumerator2.Current;
}
}
/// <summary>
/// Enumerates a possibly null enumerable.
/// If the enumerable is null, the list is empty.
/// </summary>
public static IEnumerable<T> EnumerateNull<T>(this IEnumerable<T>? items)
{
if (items is null)
yield break;
foreach (var item in items) yield return item;
}
/// <summary>
/// Applies the action <paramref name="a"/> to each item in this collection.
/// </summary>
public static void ForEach<T>(this IEnumerable<T> items, Action<T> a)
{
foreach (var item in items)
a(item);
}
/// <summary>
/// Applies the action <paramref name="a"/> to each item and its index in this collection.
/// </summary>
public static void ForEach<T>(this IEnumerable<T> items, Action<T, int> a)
{
var i = 0;
foreach (var item in items)
{
a(item, i);
i++;
}
}
/// <summary>
/// Forces enumeration of this collection and discards the result.
/// </summary>
public static void Enumerate<T>(this IEnumerable<T> items)
{
items.ForEach(_ => { });
}
/// <summary>
/// Computes a hash of a sequence.
/// </summary>
/// <typeparam name="T">The type of the item.</typeparam>
/// <param name="items">The list of items to hash.</param>
/// <returns>The hash code.</returns>
public static int SequenceHash<T>(this IEnumerable<T> items) where T : notnull
{
var h = 0;
foreach (var i in items)
h = h * 7 + i.GetHashCode();
return h;
}
/// <summary>
/// Returns the sequence with nulls removed.
/// </summary>
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> items) where T : class =>
items.Where(i => i is not null)!;
/// <summary>
/// Splits the sequence at the given index.
/// </summary>
public static (IEnumerable<T>, IEnumerable<T>) SplitAt<T>(this IEnumerable<T> items, int index)
{
var left = new List<T>();
var right = new List<T>();
var i = 0;
foreach (var item in items)
{
if (i < index)
{
left.Add(item);
}
else
{
right.Add(item);
}
i++;
}
return (left, right);
}
}
}