在C#中是否有与Python的enumerate()
和Ruby的each_with_index
相对应的功能?
我为此保留了这个扩展方法:
public static void Each<T>(this IEnumerable<T> ie, Action<T, int> action)
{
var i = 0;
foreach (var e in ie) action(e, i++);
}
然后像这样使用:
var strings = new List<string>();
strings.Each((str, n) =>
{
// hooray
});
或者允许像break
一样的行为:
public static bool Each<T>(this IEnumerable<T> ie, Func<T, int, bool> action)
{
int i = 0;
foreach (T e in ie) if (!action(e, i++)) return false;
return true;
}
var strings = new List<string>() { "a", "b", "c" };
bool iteratedAll = strings.Each ((str, n)) =>
{
if (str == "b") return false;
return true;
});
您可以执行以下操作
foreach (var it in someCollection.Select((x, i) => new { Value = x, Index = i }) )
{
if (it.Index > SomeNumber) //
}
这将为集合中的每个条目创建一个匿名类型的值。它将具有两个属性
Value
: 包含原始集合中的值Index
: 包含在集合中的索引IEnumerable<T>.ElementAt(i)
的时间复杂度为O(n)(参见Schlemiel the Painter)。如果你有一个延迟枚举的序列,并且它在评估时很昂贵并且包含大量记录,那该怎么办?使用for循环时,必须等待IEnumerable<T>.Count()
返回才能开始处理记录。因此,一般不应该使用for循环来处理 IEnumerable<T>
。 - piedarforeach (var (x, i) in someCollection.Select((x, i) => (x, i)) ) { ... }
。 - FernAndrC#的foreach循环没有内置索引。您需要在foreach循环外部添加一个整数并在每次迭代中递增它。
int i = -1;
foreach (Widget w in widgets)
{
i++;
// do something
}
或者,您可以使用标准的for循环,如下所示:
for (int i = 0; i < widgets.Length; i++)
{
w = widgets[i];
// do something
}
我喜欢使用foreach,因此我创建了一个扩展方法和一个结构:
public struct EnumeratedInstance<T>
{
public long cnt;
public T item;
}
public static IEnumerable<EnumeratedInstance<T>> Enumerate<T>(this IEnumerable<T> collection)
{
long counter = 0;
foreach (var item in collection)
{
yield return new EnumeratedInstance<T>
{
cnt = counter,
item = item
};
counter++;
}
}
并且有一个使用示例:
foreach (var ii in new string[] { "a", "b", "c" }.Enumerate())
{
Console.WriteLine(ii.item + ii.cnt);
}
有一个好处是,如果你已经习惯了Python的语法,你仍然可以使用它:
foreach (var ii in Enumerate(new string[] { "a", "b", "c" }))
除了已经给出的LINQ答案外,我还有一个"SmartEnumerable"类,它允许您获取索引和“第一个/最后一个”的信息。从语法上来说,它有点丑陋,但您可能会发现它很有用。
我们可以使用非泛型类型中的静态方法来改进类型推断,并且隐式类型转换也会有所帮助。
public static IEnumerable<Pair<Int32, X>> Ordinate<X>(this IEnumerable<X> lhs)
{
return lhs.Ordinate(0);
}
public static IEnumerable<Pair<Int32, X>> Ordinate<X>(this IEnumerable<X> lhs, Int32 initial)
{
Int32 index = initial - 1;
return lhs.Select(x => new Pair<Int32, X>(++index, x));
}
System.Tuple
可以用来代替你的 Pair
。 - Asherah我刚找到一个有趣的解决方案:
public class DepthAware<T> : IEnumerable<T>
{
private readonly IEnumerable<T> source;
public DepthAware(IEnumerable<T> source)
{
this.source = source;
this.Depth = 0;
}
public int Depth { get; private set; }
private IEnumerable<T> GetItems()
{
foreach (var item in source)
{
yield return item;
++this.Depth;
}
}
public IEnumerator<T> GetEnumerator()
{
return GetItems().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
// Generic type leverage and extension invoking
public static class DepthAware
{
public static DepthAware<T> AsDepthAware<T>(this IEnumerable<T> source)
{
return new DepthAware<T>(source);
}
public static DepthAware<T> New<T>(IEnumerable<T> source)
{
return new DepthAware<T>(source);
}
}
使用方法:
var chars = new[] {'a', 'b', 'c', 'd', 'e', 'f', 'g'}.AsDepthAware();
foreach (var item in chars)
{
Console.WriteLine("Char: {0}, depth: {1}", item, chars.Depth);
}
这是您的收藏
var values = new[] {6, 2, 8, 45, 9, 3, 0};
var indexes = Enumerable.Range(0, values.Length).ToList();
使用range函数进行索引迭代
indexes.ForEach(i => values[i] += i);
indexes.ForEach(i => Console.Write("[{0}] = {1}", i, values[i]));
这取决于您使用的类。
例如,Dictionary<(Of <(TKey, TValue>)>)类支持此操作
Dictionary<(Of <(TKey, TValue>)>)泛型类提供了从一组键到一组值的映射。
为了枚举,字典中的每个项都被视为表示值和其键的KeyValuePair<(Of <(TKey, TValue>)>)结构。返回项目的顺序是未定义的。
foreach (KeyValuePair kvp in myDictionary) {...}
foreach
的一个特性不就是可以绝对解耦地处理列表中的每个元素吗? - Konstantin A. Magg