Есть ли более эффективный способ получить эти плоские данные в словарь? - PullRequest
2 голосов
/ 22 сентября 2011

У меня есть следующий код:

public class Alert
{
    public string Alias { get; set; }
    public int ServiceHours { get; set; }
    public int TotalHoursDone { get; set; }
    public int UserId { get; set; }
    public int VehicleId { get; set; }
}

private static readonly List<Alert> AlertsToDo = new List<Alert>();

public void SomeFunction() {
    // creates a dictionary of user ids as the key with their alerts
    // (sorted by alias) as the value.
    // Just one loop needed and no awkward state logic.
    var alertsGrouped = AlertsToDo.Select(a => a.UserId)
                                  .Distinct()
                                  .ToDictionary(userId => userId,
                        userId => AlertsToDo.Where(a => a.UserId == userId)
                                            .OrderBy(a => a.Alias)
                                            .ToList());
}

Итак, у меня есть список объектов Alert. Мой запрос LINQ выводит словарь, ключом которого является UserId, а значением является список оповещений для этого UserId, отсортированный по псевдониму.

Я достаточно доволен изобретательностью этого запроса, но мне интересно, есть ли более простой способ сделать это? В частности, мне нужно использовать второй запрос для каждого ключа, чтобы создать список значений. Запрашиваемая просто из интереса, так как это достаточно быстро для работы.

Ответы [ 2 ]

3 голосов
/ 22 сентября 2011

Существует более короткий подход, который более удобочитаем, используя метод Enumerable.GroupBy.Для небольшого объема данных вы, скорее всего, не увидите разницы, в то время как большой объем данных изменит производительность.Ваш запрос сначала получает различные значения, затем фильтрует элементы по UserId.Группировка сокращает эти шаги заранее.Чтобы точно знать, что вам нужно профилировать.

Вот запрос с использованием группировки:

var query = AlertsToDo.GroupBy(a => a.UserId)
                      .ToDictionary(g => g.Key,
                                    g => g.OrderBy(a => a.Alias).ToList());
0 голосов
/ 27 октября 2011

Извините за задержку, но, как и было обещано, вот некоторые результаты теста.

Код, который я тестировал:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    public class Alert
    {
        public string Alias { get; set; }
        public int ServiceHours { get; set; }
        public int TotalHoursDone { get; set; }
        public int UserId { get; set; }
        public int VehicleId { get; set; }
    }

    private static readonly List<Alert> AlertsToDo = new List<Alert>();

    private void button1_Click(object sender, EventArgs e)
    {
        var rng = new Random();

        var watch = new System.Diagnostics.Stopwatch();
        watch.Start();
        for (int i = 0; i < 1000000; i++)
        {
            int random = rng.Next();

            AlertsToDo.Add(new Alert
            {
                Alias = random.ToString(),
                UserId = random
            });
        }
        Console.WriteLine(@"Random generation: {0}", watch.ElapsedMilliseconds);

        watch = new System.Diagnostics.Stopwatch();
        watch.Start();
        var alertsGrouped = AlertsToDo.Select(a => a.UserId)
                              .Distinct()
                              .ToDictionary(userId => userId,
                    userId => AlertsToDo.Where(a => a.UserId == userId)
                                        .OrderBy(a => a.Alias)
                                        .ToList());
        watch.Stop();
        Console.WriteLine(@"Mine: {0}", watch.ElapsedMilliseconds);
        Console.WriteLine(alertsGrouped.Count);

        watch = new System.Diagnostics.Stopwatch();
        watch.Start();
        alertsGrouped = AlertsToDo.GroupBy(a => a.UserId)
                  .ToDictionary(g => g.Key,
                                g => g.OrderBy(a => a.Alias).ToList());
        watch.Stop();
        Console.WriteLine(@"Ahmad's: {0}", watch.ElapsedMilliseconds);
        Console.WriteLine(alertsGrouped.Count);
    }
}

И вывод:

Случайная генерация: 769

Шахта: 32164861 (более 8 часов)

999798

Ахмада: 4133

999798

Неудивительно, что GroupBy работает быстреепоскольку моя версия выполняет подзапрос, но просто посмотрите, насколько быстрее!

Итак, победитель: Ахмад, очевидно.

...