在'foreach'循环中获取数组键

31

在C#中的foreach循环中,如何获取当前元素的键(key)?

例如:

PHP示例

foreach ($array as $key => $value)
{
    echo("$value is assigned to key: $key");
}

我在C#中尝试做什么:

int[] values = { 5, 14, 29, 49, 99, 150, 999 };

foreach (int val in values)
{
    if(search <= val && !stop)
    {
         // Set key to a variable
    }
}
9个回答

25

Grauenwolf的方法是使用数组进行操作的最直接和高效的方式:

可以使用for循环或创建一个临时变量,在每次通过时递增该变量。

这当然会看起来像这样:

int[] values = { 5, 14, 29, 49, 99, 150, 999 };

for (int key = 0; key < values.Length; ++key)
  if (search <= values[key] && !stop)
  {
    // set key to a variable
  }

使用.NET 3.5,您也可以采用更加功能化的方法,但这在现场会略显冗长,并且可能需要一些支持函数访问IEnumerable中的元素。如果只是这些内容,这样做有点过度,但如果您经常进行集合处理,则非常方便。


或者创建一个临时变量,在每次通过时递增。据我所记,foreach循环不保证按升序(或降序)遍历集合,只保证它会在每个元素上 恰好一次 停止,因此如果您使用外部值,则根据实现,您的解决方案可能有效也可能无效。通常它会给您想要的结果,但是例如,常见的优化是按降序解析数组(每个周期比按升序少一个机器指令)。 - mg30rg
我认为这取决于你正在迭代的可枚举类型。如果它是一个数组,我认为顺序是有保证的。 - Kyle Delaney

23

如果你想要获取关键字(也就是索引),那么你需要使用for循环。如果你实际上想要一个保存键/值的集合,那么我建议使用HashTable或者Dictionary(如果你想要使用泛型)。

Dictionary<int, string> items = new  Dictionary<int, string>();

foreach (int key in items.Keys)
{
  Console.WriteLine("Key: {0} has value: {1}", key, items[key]);
}

希望这有所帮助,
Tyler


7
使用foreach(KeyValuePair<int, string> pair in items)并引用pair.Key和pair.Value会比在每次迭代中进行查找更有效。 - Chris Ammerman

11

使用DictionaryEntry和KeyValuePair:

根据
MSDN

IDictionary<string,string> openWith = new Dictionary<string,string>()
{
   { "txt", "notepad.exe" }
   { "bmp", "paint.exe" }
   { "rtf", "wordpad.exe" }
};

foreach (DictionaryEntry de in openWith)
{
    Console.WriteLine("Key = {0}, Value = {1}", de.Key, de.Value);
}

// also

foreach (KeyValuePair<string,string> de in openWith)
{
    Console.WriteLine("Key = {0}, Value = {1}", de.Key, de.Value);
}

相关的SO问题:KeyValuePair vs DictionaryEntry


4

很遗憾,没有内置的方法可以实现这一点。要么使用 for 循环,要么创建一个临时变量,在每次通过时递增。


3

我在另一个版本的这个问题中回答过:

Foreach is for iterating over collections that implement IEnumerable. It does this by calling GetEnumerator on the collection, which will return an Enumerator.

This Enumerator has a method and a property:

* MoveNext()
* Current

Current returns the object that Enumerator is currently on, MoveNext updates Current to the next object.

Obviously, the concept of an index is foreign to the concept of enumeration, and cannot be done.

Because of that, most collections are able to be traversed using an indexer and the for loop construct.

I greatly prefer using a for loop in this situation compared to tracking the index with a local variable.

如何获取 foreach 循环的当前迭代索引?


2

如果您想循环遍历数组,实际上应该使用经典的for(;;)循环。但是,您使用PHP代码实现的类似功能在C#中可以通过Dictionary来实现:

Dictionary<int, int> values = new Dictionary<int, int>();
values[0] = 5;
values[1] = 14;
values[2] = 29;
values[3] = 49;
// whatever...

foreach (int key in values.Keys)
{
    Console.WriteLine("{0} is assigned to key: {1}", values[key], key);
}

使用 foreach(KeyValuePair<int, int> pair in values) 并引用 pair.Key 和 pair.Value 要比在每次迭代中进行查找的性能更高。 - Chris Ammerman

0

这是我刚想出来的解决方案

原始代码:

int index=0;
foreach (var item in enumerable)
{
    blah(item, index); // some code that depends on the index
    index++;
}

更新的代码

enumerable.ForEach((item, index) => blah(item, index));

扩展方法:

    public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T, int> action)
    {
        var unit = new Unit(); // unit is a new type from the reactive framework (http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx) to represent a void, since in C# you can't return a void
        enumerable.Select((item, i) => 
            {
                action(item, i);
                return unit;
            }).ToList();

        return pSource;
    }

0

你可以使用扩展方法自己实现这个功能。例如,下面是一个在列表上工作的KeyValuePairs扩展方法的实现:

public struct IndexValue<T> {
    public int Index {get; private set;}
    public T Value {get; private set;}
    public IndexValue(int index, T value) : this() {
        this.Index = index;
        this.Value = value;
    }
}

public static class EnumExtension
{
    public static IEnumerable<IndexValue<T>> KeyValuePairs<T>(this IList<T> list) {
        for (int i = 0; i < list.Count; i++)
            yield return new IndexValue<T>(i, list[i]);
    }
}

-10

myKey = Array.IndexOf(values, val);

的含义是:在数组values中找到值为val的元素,并返回该元素在数组中的索引位置,将其赋值给变量myKey。

3
这不是个好主意。Array.IndexOf基本上是一个时间复杂度为O(n)的搜索算法。如果你需要执行n次这样的搜索,那么整体的时间复杂度最差情况下会变成O(n^2)。换句话说,一个包含100个数据项的数组最坏情况下可能需要进行10000次比较。 - Jonathan Allen
3
如果数组中有重复的项,效率先不考虑,你将获得第一个重复项的索引,而不一定是你要查找的那个。比如,一个数组{ 5, 14, 5, 29, ... },当'val'为5时,即使你在第三个元素上,你始终会得到零作为它的索引。 - Andrew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接