Вернуть модальное среднее в LINQ (Mode) - PullRequest
1 голос
/ 24 июня 2010

Я не уверен, что CopyMost является правильным термином для использования здесь, но это термин, который использовал мой клиент («Протокол данных CopyMost»). Похоже, он хочет режим? У меня есть набор данных:

Increment    Value
.02            1
.04            1
.06            1
.08            2
.10            2

Мне нужно вернуть, какое значение встречается чаще всего «CopyMost». В этом случае значение равно 1. Сейчас я планировал написать метод расширения для IEnumerable, чтобы сделать это для целочисленных значений. Есть ли что-то встроенное в Linq, которое уже делает это легко? Или мне лучше написать метод расширения, который бы выглядел примерно так

records.CopyMost(x => x.Value);

EDIT

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

records.CopyMost(x => x.Value, x => x == 0);

В этом случае x.Value будет int, а если счетчик 0 будет таким же, как счетчик 1 и 3, он будет привязан к 0.

Ответы [ 3 ]

4 голосов
/ 24 июня 2010

Ну, вот один из вариантов:

var query = (from item in data
             group 1 by item.Value into g
             orderby g.Count() descending
             select g.Key).First();

В основном мы используем GroupBy для группировки по значению - но все, что нас интересует для каждой группы, это размер группы и клавиша (которая это первоначальное значение). Мы сортируем группы по размеру и выбираем первый элемент (элемент с наибольшим количеством элементов).

Это помогает?

2 голосов
/ 24 июня 2010

Джон опередил меня, но термин, который вы ищете: Модальное среднее .

Редактировать:

Если я 'm right Если вы считаете, что это модальное среднее значение, вам нужно следующее:

var i = (from t in data
         group t by t.Value into aggr
         orderby aggr.Count() descending
         select aggr.Key).First();
0 голосов
/ 30 апреля 2014

Этот метод несколько раз обновлялся в моем коде на протяжении многих лет.Это стало очень важным методом, и он сильно отличается от того, что было раньше.Я хотел предоставить самую свежую версию на тот случай, если кто-то захочет добавить CopyMost или Modal Average в качестве расширения linq.

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

public static K CopyMost<T, K>(this IEnumerable<T> records, Func<T, K> propertySelector, Func<K, bool> tieBreaker)
{
    var grouped = records.GroupBy(x => propertySelector(x)).Select(x => new { Group = x, Count = x.Count() });
    var maxCount = grouped.Max(x => x.Count);
    var subGroup = grouped.Where(x => x.Count == maxCount);

    if (subGroup.Count() == 1)
        return subGroup.Single().Group.Key;
    else
        return subGroup.Where(x => tieBreaker(x.Group.Key)).Single().Group.Key;
}

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

public static K CopyMost<T, K>(this IEnumerable<T> records, Func<T, K> propertySelector)
{
    return records.GroupBy(x => propertySelector(x)).OrderByDescending(x => x.Count()).Select(x => x.Key).First();
}
...