c# - 如何评估 IEnumerable同时在 C# 中对其第一个和/或最后一个元素进行特殊处理?
问题描述
这是一个更一般的问题形式,我怎样才能对列表的第一个和最后一个元素做一些特别的事情?更具体的问题很容易回答。我们知道第一个和最后一个元素的索引,因此我们可以直接访问它们或根据这些值测试索引变量。例如:
for (int i = 0; i < values.Count; ++i)
{
if (i == values.Count - 1)
{
// do something with last element
}
else
{
// do something else
}
}
但有时我需要用IEnumerable<T>
. 例如:
public static Bar TransformFoo(Foo value)
{
if (isLast /* how do we know this? */)
{
// do something with the last element
}
else
{
// do something else
}
}
public static IEnumerable<Bar> TransformFooSequence(IEnumerable<Foo> source)
{
return source.Select(TransformFoo);
}
由于这是一种常见模式,我想以一般方式解决它(而不是像过去那样为每种情况编写自定义 for 循环)。一种选择是使用 将序列转换为列表ToList()
或使用 计算元素Count()
。这两种情况的问题是解决方案涉及评估整个序列,这可能非常昂贵。
所以问题是,我如何评估一个IEnumerable<T>
序列,同时对其第一个和/或最后一个元素进行特殊处理,同时以一般方式保持对该序列的惰性评估?
解决方案
解决这个问题的一种方法是创建一个新的扩展方法,用于IEnumerable<T>
返回源序列的元素以及关于它们位置的语义信息。如果源序列的元素具有类型T
,则扩展方法将返回类型的元组(T, PositionFlags)
。这是代码:
[Flags]
enum PositionFlags
{
None = 0,
First = 1,
Last = 2
}
public static IEnumerable<(T value, PositionFlags flags)> WithPositions<T>(
this IEnumerable<T> source)
{
using (var enumerator = source.GetEnumerator())
{
if (!enumerator.MoveNext())
{
yield break;
}
T value = enumerator.Current;
PositionFlags flags = PositionFlags.First;
while (enumerator.MoveNext())
{
yield return (value, flags);
value = enumerator.Current;
flags = PositionFlags.None;
}
flags |= PositionFlags.Last;
yield return (value, flags);
}
}
然后我们可以传递位置信息以对序列中的第一个和/或最后一个项目进行特殊处理。例如:
Bar TransformFoo(Foo value, bool isLast)
{
if (isLast)
{
// do something with the last element
}
else
{
// do something else
}
}
IEnumerable<Bar> TransformFooSequence(IEnumerable<Foo> source)
{
return source
.WithPositions()
.Select(entry => TransformFoo(
entry.value,
(entry.flags & PositionFlags.Last) == PositionFlags.Last));
}
推荐阅读
- r - R按近似值分组
- api - LinkedIn API 是否允许您分析公司页面和个人资料随时间推移的追随者增长情况?
- java - jni.h 未找到(在 20.04 上构建 VBox)
- excel - 如何过滤并自动将数据填充到新工作表中?
- postgresql - Sequelize - 从同一个表中左连接 MAX 日期
- python - 如果 comment.name == 用户无法正常工作
- version - 旧版 SAS
- python-3.x - 如何使用 PANDAS 在 CSV 文件中查找一年的最大数量?
- php - 如何正确格式化 app.yaml 以使用 PHP 后端托管 Flutter Web 应用程序
- python - 热图可视化 Altair