Карта и уменьшение в .NET

Ответы:

299

Linq-эквиваленты Map и Reduce: если вам повезло иметь linq, вам не нужно писать свою собственную карту и сокращать функции. C # 3.5 и Linq уже есть, хотя и под разными именами.

  • Карта это Select:

    Enumerable.Range(1, 10).Select(x => x + 2);
  • Уменьшить это Aggregate:

    Enumerable.Range(1, 10).Aggregate(0, (acc, x) => acc + x);
  • Фильтр это Where:

    Enumerable.Range(1, 10).Where(x => x % 2 == 0);

https://www.justinshield.com/2011/06/mapreduce-in-c/

Тони
источник
1
Перевод правильный, но в нем не хватает ключевого момента. Шаг shuffle в редукте карты является критически важным для редукции карты, но он не отображается в имени, и для него не нужно писать никакого кода. Он управляется исключительно ключом, который извлекается на шаге карты. Ответ Джоэла Мартинеса подчеркивает, что на мой взгляд лучше.
xtofs
2
Ссылка не работает, правильная ссылка: justinshield.com/2011/06/mapreduce-in-c
Александру-Дан Поп
12
Почему они просто не называют это Reduceвместо Aggregate... MS просто любит раздражать программистов
Джон Хенкель
13
@JohnHenckel, я определенно не авторитетный источник, но я почти уверен, что это происходит из SQL. Я считаю, что linq был изначально куплен как способ облегчения взаимодействия с sql в C #. Когда вы называете функции в этом мире, агрегат начинает звучать немного более знакомо, чем «уменьшить» по сравнению с такими вещами, как Select и Group By. Я не говорю, что это правильно, это бесит меня, но я думаю, что причина этого.
Эллиот Блэкберн
18

Классы задач, которые хорошо подходят для решения стиля mapreduce, являются проблемами агрегирования. Извлечение данных из набора данных. В C # можно использовать LINQ для программирования в этом стиле.

Из следующей статьи: http://codecube.net/2009/02/mapreduce-in-c-using-linq/

метод GroupBy действует как карта, а метод Select выполняет работу по сокращению промежуточных результатов до окончательного списка результатов.

var wordOccurrences = words
                .GroupBy(w => w)
                .Select(intermediate => new
                {
                    Word = intermediate.Key,
                    Frequency = intermediate.Sum(w => 1)
                })
                .Where(w => w.Frequency > 10)
                .OrderBy(w => w.Frequency);

Для распределенной части вы можете проверить DryadLINQ: http://research.microsoft.com/en-us/projects/dryadlinq/default.aspx

Джоэл Мартинес
источник
3

Так как я никогда не могу вспомнить , что LINQ называет его Where, Selectи Aggregateвместо того Filter, Mapи Reduceпоэтому я создал несколько методов расширения вы можете использовать:

IEnumerable<string> myStrings = new List<string>() { "1", "2", "3", "4", "5" };
IEnumerable<int> convertedToInts = myStrings.Map(s => int.Parse(s));
IEnumerable<int> filteredInts = convertedToInts.Filter(i => i <= 3); // Keep 1,2,3
int sumOfAllInts = filteredInts.Reduce((sum, i) => sum + i); // Sum up all ints
Assert.Equal(6, sumOfAllInts); // 1+2+3 is 6

Вот 3 метода (из https://github.com/cs-util-com/cscore/blob/master/CsCore/PlainNetClassLib/src/Plugins/CsCore/com/csutil/collections/IEnumerableExtensions.cs ):

public static IEnumerable<R> Map<T, R>(this IEnumerable<T> self, Func<T, R> selector) {
    return self.Select(selector);
}

public static T Reduce<T>(this IEnumerable<T> self, Func<T, T, T> func) {
    return self.Aggregate(func);
}

public static IEnumerable<T> Filter<T>(this IEnumerable<T> self, Func<T, bool> predicate) {
    return self.Where(predicate);
}

Еще некоторые подробности из https://github.com/cs-util-com/cscore#ienumerable-extensions :

введите описание изображения здесь

CsUtil.com
источник