Обработка рейтинговых данных с C # и LINQ - PullRequest
2 голосов
/ 05 марта 2010

У меня есть объект в списке, который мне нужно ранжировать несколькими разными способами.В настоящее время код довольно громоздкий, так как он требует от меня индивидуального обращения к каждому столбцу.Пример:

public class Data
{
    public int AValue { get; set; }
    public int ARanking { get; set; }
    public int BValue { get; set; }
    public int BRanking { get; set; }
    public int CValue { get; set; }
    public int CRanking { get; set; }
}

public class Container
{
    public List<Data> RankingData { get; set; }

    public void RankData()
    {
        int count = 1;

        foreach (Data item in RankingData.OrderBy(d => d.AValue))
        {
            item.ARanking = count;
            count++;
        }

        count = 1;

        foreach (Data item in RankingData.OrderBy(d => d.BValue))
        {
            item.BRanking = count;
            count++;
        }

        count = 1;

        foreach (Data item in RankingData.OrderBy(d => d.CValue))
        {
            item.CRanking = count;
            count++;
        }
    }
}

Проблема, которую я пытаюсь решить, я хочу написать примерно так:

public void RankData<V, R>()
{
    int count = 1;

    foreach(Data item in RankingData.OrderBy(V))
    {
        item.R = count;
        count++;
    }
}

Так что мне нужно изменить логику ранжирования (например,обрабатывать правила разрыва связей), что я пишу код один раз вместо того, чтобы копировать код 20 раз, чтобы правила соответствовали.Чего мне не хватает?

ОБНОВЛЕНИЕ

Используя решение Tanzelax в качестве основы, я разработал класс расширения:

public static class RankingExtension
{
    public static void SetRanking<TKey>(this List<Data> dataSet, bool Ascending, Func<Data, TKey> getOrderBy, Action<Data, int> setRank)
        where TKey : IComparable
    {
        var ordered = (Ascending) ? dataSet.OrderBy(getOrderBy) : dataSet.OrderByDescending(getOrderBy);

        int i = 1;
        foreach (Data item in ordered)
        {
            setRank(item, i);
            i++;
        }
    }
}

Iпришлось добавить переключатель, чтобы я мог контролировать, сортируется ли поле по возрастанию или нет.И в моих тестовых сценариях он выдает соответствующий вывод:

    List<Data> test = new List<Data>();
    test.Add(new Data { AValue = 25, BValue = 1.25, CValue = 99.99 });
    test.Add(new Data { AValue = 89, BValue = 2.10, CValue = 1.01 });
    test.Add(new Data { AValue = 10, BValue = 6, CValue = 45.45 });
    test.Add(new Data { AValue = 15, BValue = 2.33, CValue = 2.99 });
    test.Add(new Data { AValue = 90, BValue = 5.43, CValue = 27.89 });

    test.SetRanking(false, d => d.AValue, (d, i) => d.ARank = i);
    test.SetRanking(false, d => d.BValue, (d, i) => d.BRank = i);
    test.SetRanking(true, d => d.CValue, (d, i) => d.CRank = i);

Ответы [ 3 ]

1 голос
/ 06 марта 2010

Это похоже на ответ Танзелакса, но это общий метод расширения.

public static void RankData<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector,
    Action<TSource, int> rankSetter
)
{
    int count = 1;
    foreach (var item in source.OrderBy(keySelector))
    {
        rankSetter(item, count);
        ++count;
    }
}

Его также можно назвать похожим на ответ Танзелакса.

RankingData.RankData(d => d.AValue, (d,i) => d.ARanking = i);
1 голос
/ 05 марта 2010

Не проверено, но как-то так:

void SetRanking(this List<Data> dataSet, Func<Data,int> getOrderBy, Action<Data,int> setRank)
{
    var ordered = dataSet.OrderBy(getOrderBy).ToArray();

    int i = i;
    foreach (Data item in ordered)
    {
        setRank(item, i);
        i++;
    }
}

RankingData.SetRanking(d => d.AValue, (d,i) => d.ARanking = i);
RankingData.SetRanking(d => d.BValue, (d,i) => d.BRanking = i);
RankingData.SetRanking(d => d.CValue, (d,i) => d.CRanking = i);
0 голосов
/ 05 марта 2010

Передайте Func<Data,K>, который возвращает ключ ранжирования. K должен реализовать IComparable

public static void Rank<K>( IEnumerable<Data> source, Func<Data,K> rankBy ) where K : IComparable
{
   int count = 1;
   foreach (var item in source.OrderBy( rankBy ))
   {
       item.R = count;
       ++count;
   }
}
...