Как правильно перевести результат "var" лямбда-выражения в конкретный тип? - PullRequest
3 голосов
/ 26 марта 2010

Так что я пытаюсь узнать больше о лямбда-выражениях. Я прочитал этот вопрос на стеке потока, согласился с выбранным ответом и попытался реализовать алгоритм, используя консольное приложение на C #, используя простое выражение LINQ.

Мой вопрос: как мне перевести «результат var» лямбда-выражения в пригодный для использования объект, который я могу затем распечатать результат?

Буду также признателен за подробное объяснение того, что происходит, когда я объявляю outer => outer.Value.Frequency

(я читал многочисленные объяснения лямбда-выражений, но дополнительные разъяснения помогли бы)

C#
//Input : {5, 13, 6, 5, 13, 7, 8, 6, 5}

//Output : {5, 5, 5, 13, 13, 6, 6, 7, 8}

//The question is to arrange the numbers in the array in decreasing order of their frequency, preserving the order of their occurrence.

//If there is a tie, like in this example between 13 and 6, then the number occurring first in the input array would come first in the output array.

      List<int> input = new List<int>();
      input.Add(5);
      input.Add(13);
      input.Add(6);
      input.Add(5);
      input.Add(13);
      input.Add(7);
      input.Add(8);
      input.Add(6);
      input.Add(5);      

      Dictionary<int, FrequencyAndValue> dictionary = new Dictionary<int, FrequencyAndValue>();

      foreach (int number in input)
      {
        if (!dictionary.ContainsKey(number))
        {
          dictionary.Add(number, new FrequencyAndValue(1, number) );
        }
        else
        {
          dictionary[number].Frequency++;
        }
      }

      var result = dictionary.OrderByDescending(outer => outer.Value.Frequency);

      // How to translate the result into something I can print?? 

Ответ с командами печати см. мой ответ здесь .

Ответы [ 4 ]

27 голосов
/ 26 марта 2010

как мне перевести "результат var" лямбда-выражения в пригодный для использования объект, который я могу затем распечатать результат?

Прежде всего, «лямбда-выражение» - это только часть выражения, имеющая форму a=>b. Остальная часть вашего запроса - это просто вызов метода, который принимает лямбду в качестве аргумента.

В любом случае, если бы я мог научить людей одной вещи о LINQ, это было бы так: «результат» - это не результаты запроса, это - это сам запрос .

Если вы хотите увидеть результаты, задайте запрос для каждого результата:

foreach(var item in result)
    Console.WriteLine(item.ToString());

Я также был бы признателен за подробное объяснение того, что происходит, когда я объявляю external => external.Value.Frequency

Конечно. Мы начинаем с разработки типов всего, что с этим связано. Мы видим, что лямбда-это функция, которая принимает KeyValuePair и возвращает int, поэтому мы генерируем метод

static private int MyLambda(KeyValuePair<int, FrequencyAndValue> outer)
{
    return outer.Value.Frequency;
}

Затем мы возьмем этот метод и создадим из него делегата:

var result = dictionary.OrderByDescending(
    new Func<KeyValuePair<int, FrequencyAndValue>, int>(MyLambda));

и переписать вызов метода расширения:

var result = Enumerable.OrderByDescending<KeyValuePair<int, FrequencyAndValue>, int>(
    dictionary,
    new Func<KeyValuePair<int, FrequencyAndValue>, int>(MyLambda));

и переписать переменную:

IOrderedEnumerable<KeyValuePair<int, FrequencyAndValue>> result =
    Enumerable.OrderByDescending<KeyValuePair<int, FrequencyAndValue>, int>(
    dictionary,
    new Func<KeyValuePair<int, FrequencyAndValue>, int>(MyLambda));

Надеюсь, вы согласитесь, что код, который вы набрали, намного более читабелен, чем этот беспорядок. Тип выводных камней.

Результатом является объект, который представляет возможность сортировать этот словарь по заданному ключу. Внимательно прочитайте: это означает способность сортировать словарь по этому ключу. На самом деле он этого не делает, пока вы не попросите результат; до сих пор все, что это - объект, который говорит: «когда запрашивается результат, отсортируйте словарь по этому ключу».

Предположим, вы просите о результате. Как он вычисляет отсортированный список? Он запрашивает словарь для каждого элемента. Затем он вызывает MyLambda для каждого элемента, который возвращает целое число, поэтому у нас теперь есть пара словарных значений и целых чисел в словаре. Затем он строит список пар, отсортированных по этому целому числу. Затем он раздает элементы этого списка по одному, как вы их просите.

Мы видим, что лямбда-функция - это функция, которая принимает KeyValuePair и возвращает целое число "- Как вы это определили? Я не вижу его по возвращаемому значению метода или документально подтверждено в OrderByDescending ().

Ах, я вижу замешательство; по педагогическим соображениям я выдвинул немного выше относительно точного порядка, в котором происходит семантический анализ.

Как мы делаем этот вывод типа, является одной из наиболее тонких и интересных частей C #.

Вот как это работает.

Мы видим, что OrderByDescending объявлен как:

static IOrderedEnumerable<T> OrderByDescending<T, K>(
    this IEnumerable<T> sequence, 
    Func<T, K> keyExtractor)

и мы видим, что у нас есть потенциальный вызов этого метода:

OrderByDescending(dictionary, o=>o.Value.Frequency)

Но мы не знаем, что такое Т и К. Итак, мы начнем с рассмотрения всего, что НЕ является лямбдой. Ваш словарь реализует IEnumerable<KeyValuePair<int, FrequencyOrValue>>, поэтому мы начнем с того, что "T, вероятно, KeyValuePair<int, FrequencyOrValue>".

На данный момент больше ничего мы не можем вывести из вещей, которые не являются лямбдами, поэтому мы начинаем смотреть на лямбды. Мы видим, что у нас есть лямбда o=>o.Value.Frequency, и до сих пор мы определили, что типом keyExtractor является Func<KeyValuePair<int, FrequencyOrValue>, K>, и мы все еще ищем K. Итак, мы говорим, предположим, что лямбда на самом деле была:

(KeyValuePair<int, FrequencyOrValue> o)=>{return o.Value.Frequency;}

И мы спрашиваем это связывает ? ДА! Да, это так. Мы можем успешно скомпилировать эту лямбду без ошибок, и когда мы делаем это, мы видим, что все ее операторы возврата возвращают int.

Поэтому мы выводим, что K - это int, и теперь у нас есть полный анализ типа всего этого.

Это довольно простой вывод; они могут стать намного страннее. Смотрите архив «вывод типа» в моем блоге, если эта тема особенно вас интересует.

http://blogs.msdn.com/ericlippert/archive/tags/Type+Inference/default.aspx

В частности, вот мое видео, объясняющее вышеизложенное, а также несколько других интересных случаев:

http://blogs.msdn.com/ericlippert/archive/2006/11/17/a-face-made-for-email-part-three.aspx

2 голосов
/ 26 марта 2010

Функция OrderByDescending вернет IEnumerable, фактически IOrderedEnumerable, где TSource является источником типа исходного перечисляемого.

Когда вы работаете со словарем, OrderByDescending вернет:

 IOrderedEnumerable<KeyValuePair<int, FrequencyAndValue>>

объект, который будет упорядочен согласно предоставленному выражению.

1 голос
/ 26 марта 2010
var result = dictionary.OrderByDescending(outer => outer.Value.Frequency);

Эта строка дает вам IOrderedEnumerable<KeyValuePair<int, FrequencyAndValue>> вызванный результат.Что касается лямбды, она имеет тип

Func<KeyValuePair<int,FrequencyAndValue>, int>

, что означает, что она принимает параметр KeyValuePair<int, FrequencyAndValue> (который вы называете внешним) и возвращает целое число, соответствующее свойству Frequency значения пары.Таким образом, полученный IOrderedEnumerable сортируется по частоте в обратном порядке.

0 голосов
/ 26 марта 2010

Ради документации полного ответа я напечатал вывод, используя более общий «элемент», а также более конкретный IOrderedEnumerable.

C#
static void Main(string[] args)
    {

      //Input : {5, 13, 6, 5, 13, 7, 8, 6, 5}

      //Output : {5, 5, 5, 13, 13, 6, 6, 7, 8}

      //The question is to arrange the numbers in the array in decreasing order of their frequency, preserving the order of their occurrence.

      //If there is a tie, like in this example between 13 and 6, then the number occurring first in the input array would come first in the output array.

      List<int> input = new List<int>();
      input.Add(5);
      input.Add(13);
      input.Add(6);
      input.Add(5);
      input.Add(13);
      input.Add(7);
      input.Add(8);
      input.Add(6);
      input.Add(5);      

      Dictionary<int, FrequencyAndValue> dictionary = new Dictionary<int, FrequencyAndValue>();

      foreach (int number in input)
      {
        if (!dictionary.ContainsKey(number))
        {
          dictionary.Add(number, new FrequencyAndValue(1, number) );
        }
        else
        {
          dictionary[number].Frequency++;
        }
      }

      var result = dictionary.OrderByDescending(outer => outer.Value.Frequency);

      // BEGIN Priting results with the help of stackoverflow answers 
      Console.Write("With Items: ");    
      foreach (var item in result)
      {
        for (int i = 0; i < item.Value.Frequency; i++)
        {
          Console.Write(item.Value.Value + " ");
        }
        //Console.WriteLine(item.Value.Frequency + " " + item.Value.Value);
      }
      Console.WriteLine();

      Console.Write("With IOrderedEnumerable: ");    
      IOrderedEnumerable<KeyValuePair<int, FrequencyAndValue>> myres = result;
      foreach (KeyValuePair<int, FrequencyAndValue> fv in myres)
      {
        for(int i = 0; i < fv.Value.Frequency; i++ )
        {
          Console.Write(fv.Value.Value + " ");
        }
      }
      Console.WriteLine();
      // END Priting results with the help of stackoverflow answers 
      Console.ReadLine();
    }
    class FrequencyAndValue
    {
      public int Frequency{ get; set;}
      public int Value{ get; set;}
      public FrequencyAndValue(int myFreq, int myValue)
      {
        Value = myValue;
        Frequency = myFreq;
      }
    }
}
...