EnumerableExtensions.cs
9.04 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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
using NCC.Dependency;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace NCC.Common.Extension
{
/// <summary>
/// Enumerable集合扩展方法
/// </summary>
[SuppressSniffer]
public static class EnumerableExtensions
{
/// <summary>断言集合中的元素符合指定表达式,否则抛出异常</summary>
/// <typeparam name="T">集合项类型</typeparam>
/// <param name="source">源集合</param>
/// <param name="predicate">元素判断表达式</param>
/// <param name="errorSelector">异常选择器</param>
/// <returns>筛选过的集合</returns>
public static IEnumerable<T> Assert<T>(this IEnumerable<T> source,
Func<T, bool> predicate,
Func<T, Exception> errorSelector = null)
{
foreach (T item in source)
{
bool success = predicate(item);
if (!success)
{
throw errorSelector?.Invoke(item) ?? new InvalidOperationException("Sequence contains an invalid item.");
}
yield return item;
}
}
/// <summary>
/// 确定第一个序列的末尾是否等价于第二个序列。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="first">第一个序列</param>
/// <param name="second">第二个序列</param>
/// <returns></returns>
public static bool EndsWith<T>(this IEnumerable<T> first, IEnumerable<T> second)
{
return EndsWith(first, second, null);
}
/// <summary>
/// 确定第一个序列的末尾是否等价于第二个序列
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="first">第一个序列</param>
/// <param name="second">第二个序列</param>
/// <param name="comparer">元素比较方式</param>
/// <returns></returns>
public static bool EndsWith<T>(this IEnumerable<T> first, IEnumerable<T> second, IEqualityComparer<T> comparer)
{
if (first == null) throw new ArgumentNullException(nameof(first));
if (second == null) throw new ArgumentNullException(nameof(second));
comparer = comparer ?? EqualityComparer<T>.Default;
int? secondCount = second.TryGetCollectionCount();
if (secondCount != null)
{
int? firstCount = first.TryGetCollectionCount();
if (firstCount != null && secondCount > firstCount)
{
return false;
}
return Impl(second, secondCount.Value);
}
List<T> secondList;
return Impl(secondList = second.ToList(), secondList.Count);
bool Impl(IEnumerable<T> snd, int count)
{
using (var firstIter = first.Reverse().Take(count).Reverse().GetEnumerator())
{
return snd.All(item => firstIter.MoveNext() && comparer.Equals(firstIter.Current, item));
}
}
}
/// <summary>
/// 打乱一个集合的项顺序,将一个集合洗牌
/// </summary>
public static IEnumerable<TSource> Shuffle<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
return source.OrderBy(m => Guid.NewGuid());
}
/// <summary>
/// 将集合展开并分别转换成字符串,再以指定的分隔符衔接,拼成一个字符串返回。默认分隔符为逗号
/// </summary>
/// <param name="collection"> 要处理的集合 </param>
/// <param name="separator"> 分隔符,默认为逗号 </param>
/// <returns> 拼接后的字符串 </returns>
public static string ExpandAndToString<T>(this IEnumerable<T> collection, string separator = ",")
{
return collection.ExpandAndToString(item => item?.ToString() ?? string.Empty, separator);
}
/// <summary>
/// 循环集合的每一项,调用委托生成字符串,返回合并后的字符串。默认分隔符为逗号
/// </summary>
/// <param name="collection">待处理的集合</param>
/// <param name="itemFormatFunc">单个集合项的转换委托</param>
/// <param name="separator">分隔符,默认为逗号</param>
/// <typeparam name="T">泛型类型</typeparam>
/// <returns></returns>
public static string ExpandAndToString<T>(this IEnumerable<T> collection, Func<T, string> itemFormatFunc, string separator = ",")
{
collection = collection as IList<T> ?? collection.ToList();
if (!collection.Any())
{
return string.Empty;
}
StringBuilder sb = new StringBuilder();
int i = 0;
int count = collection.Count();
foreach (T item in collection)
{
if (i == count - 1)
{
sb.Append(itemFormatFunc(item));
}
else
{
sb.Append(itemFormatFunc(item) + separator);
}
i++;
}
return sb.ToString();
}
/// <summary>
/// 集合是否为空
/// </summary>
/// <param name="collection"> 要处理的集合 </param>
/// <typeparam name="T"> 动态类型 </typeparam>
/// <returns> 为空返回True,不为空返回False </returns>
public static bool IsEmpty<T>(this IEnumerable<T> collection)
{
collection = collection as IList<T> ?? collection.ToList();
return !collection.Any();
}
/// <summary>
/// 根据第三方条件是否为真来决定是否执行指定条件的查询
/// </summary>
/// <param name="source"> 要查询的源 </param>
/// <param name="predicate"> 查询条件 </param>
/// <param name="condition"> 第三方条件 </param>
/// <typeparam name="T"> 动态类型 </typeparam>
/// <returns> 查询的结果 </returns>
public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> source, Func<T, bool> predicate, bool condition)
{
source = source as IList<T> ?? source.ToList();
return condition ? source.Where(predicate) : source;
}
/// <summary>
/// 将字符串集合按指定前缀排序
/// </summary>
public static IEnumerable<T> OrderByPrefixes<T>(this IEnumerable<T> source, Func<T, string> keySelector, params string[] prefixes)
{
List<T> all = source.OrderBy(keySelector).ToList();
List<T> result = new List<T>();
foreach (string prefix in prefixes)
{
List<T> tmpList = all.Where(m => keySelector(m).StartsWith(prefix)).OrderBy(keySelector).ToList();
all = all.Except(tmpList).ToList();
result.AddRange(tmpList);
}
result.AddRange(all);
return result;
}
/// <summary>
/// 根据指定条件返回集合中不重复的元素
/// </summary>
/// <typeparam name="T">动态类型</typeparam>
/// <typeparam name="TKey">动态筛选条件类型</typeparam>
/// <param name="source">要操作的源</param>
/// <param name="keySelector">重复数据筛选条件</param>
/// <returns>不重复元素的集合</returns>
public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
source = source as IList<T> ?? source.ToList();
return source.GroupBy(keySelector).Select(group => group.First());
}
#region Internal
internal static int? TryGetCollectionCount<T>(this IEnumerable<T> source)
{
switch (source)
{
case null:
throw new ArgumentNullException(nameof(source));
case ICollection<T> collection:
return collection.Count;
case IReadOnlyCollection<T> collection:
return collection.Count;
default:
return null;
}
}
static int CountUpTo<T>(this IEnumerable<T> source, int max)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (max < 0) throw new ArgumentOutOfRangeException(nameof(max), "The maximum count argument cannot be negative.");
var count = 0;
using (var e = source.GetEnumerator())
{
while (count < max && e.MoveNext())
{
count++;
}
}
return count;
}
#endregion
}
}