0

在下面的代码中,我错过了编译器如何知道 k 映射到 musos,以及为什么 v 是自动递增的:

string[] musos = { "David Gilmour", "Rick Wright", "Roger Waters", "Nick Mason" };
int[] keys = new int[] { 1, 4, 3, 2 };

var sorted = musos.Select((k, v) => new { Value = k, Key = keys[v] })
    .OrderBy(k => k.Key)
    .Select(v => v.Value.Split().Last())

foreach (var item in sorted)
{
    Console.WriteLine(item);
}

代码完美运行,返回:

吉尔摩·梅森·沃特斯·赖特

4

2 回答 2

2

好吧,我们去msdn

public static IEnumerable<TResult> Select<TSource, TResult>(
    this IEnumerable<TSource> source,
    Func<TSource, int, TResult> selector
)

通过合并元素的索引将序列的每个元素投影到新形式中。

所以在你选择时,你得到了元素 (k) 和它的索引 (v)。

所以

  • 带 0(v) 的 David Gilmour(k)(musos 数组中 David Gilmour 的索引)
  • Rick Wright(k) 和 1(v)(Rick Wright 在 musos 数组中的索引)
  • 等等

而且您的代码有效,因为 keys 数组至少与 musos 数组一样长,所以

keys[0] = 1 //  0 = v
keys[1] = 4 // 1 = v
keys[2] = 3 // 2 = v
keys[3] = 2 // 3 = v
于 2013-03-08T14:46:08.963 回答
1

因为在这种情况下,Select 接受一个 Func 委托,它将 IEnumerable 的每个元素作为键传递给该委托,以及该元素在可枚举中的位置。在您的情况下,元素是来自 musos 数组的字符串。

以下代码:

string[] musos = { "David Gilmour", "Rick Wright", "Roger Waters", "Nick Mason" };
int[] keys = new int[] { 1, 4, 3, 2 };

musos.Select((k, v) => new { Value = k, Key = keys[v] })

可以解释为:

musos.Select((Func<string, int, ANONYMOUS_TYPE>)delegate(string k, int v){
                   return new ANONYMOUS_TYPE() { Value = k, Key = keys[v] };
             });

上面,ANONYMOUS_TYPE类型只是编译器自动生成的匿名类型的占位符,用于表示和保存 lambda 表达式返回的对象,这些对象具有两个公共属性:Value类型stringKey类型int。这种类型可能如下所示:

class ANONYMOUS_TYPE
{
    public ANONYMOUS_TYPE()
    {
    }

    public string Value { get; set; }

    public int Key { get; set; }
}

您现在可以想象在这种情况下 Select 的实现:

IEnumerable<ANONYMOUS_TYPE> Select<string, ANONYMOUS_TYPE>(IEnumerable<string> musos, Func<string, int, ANONYMOUS_TYPE> selector)
{
    int pos = 0; 
    var results = new List<ANONYMOUS_TYPE>();
    foreach(string k in musos)
    {
        results.add(selector(k, pos));
        pos++;
    }
    return (IEnumerable<ANONYMOUS_TYPE>)results;
}
于 2013-03-08T14:40:36.903 回答