2015-02-06 3 views
0

У меня есть список простых объектов:Linq Список транспонирования

var r = new List 
     { 
      new { Id = 1, Value = 2, DateTime = DateTime.Parse("10.10.2014")}, 
      new { Id = 2, Value = 3, DateTime = DateTime.Parse("10.10.2014")}, 
      new { Id = 3, Value = 4, DateTime = DateTime.Parse("10.10.2014")}, 
      new { Id = 1, Value = 5, DateTime = DateTime.Parse("11.10.2014")}, 
      new { Id = 2, Value = 6, DateTime = DateTime.Parse("11.10.2014")} 
     }; 

Я хочу, чтобы получить объект, например:

DateTime | 1 | 2 | 3 | 
10.10.2014 | 2 | 3 | 4 | 
11.10.2014 | 5 | 6 | | 

Есть ли хороший запрос LINQ к этому? Smth, как pivot/univot в sql, может быть?

ответ

0

Вы ищете простой GroupBy:

var result = r.GroupBy(x => x.DateTime) 
       .Select (grp => new 
       { 
        DateTime = grp.Key, 
        _1 = grp.Where(x => x.Id == 1).Select(x => x.Value).Cast<Int32?>().FirstOrDefault(), 
        _2 = grp.Where(x => x.Id == 2).Select(x => x.Value).Cast<Int32?>().FirstOrDefault(), 
        _3 = grp.Where(x => x.Id == 3).Select(x => x.Value).Cast<Int32?>().FirstOrDefault() 
       }); 

result теперь:

enter image description here

+0

Я думаю, что предпочитаю использовать '.Select (x => new Nullable (x.Value)' than '.Выберите (x => x.Value) .Cast ()' просто потому, что его более безопасный тип. – Aron

1

Попробуйте это:

r.ToLookup(t => t.id, t=>t.DateTime) 

И если это не работает, прочитайте this

Вы хотите сгруппировать список в соответствии с идентификатором, а затем ввести полученный список по словарю. Вы должны иметь возможность сделать это с помощью некоторой комбинации GroupBy, которая создает список сгруппированных списков и ToDictionary(), который создает, позволяет вам указать свойство объекта в качестве ключа и создать из него словарь.

0

Если число ИДС не известны во время компиляции, то нет никакого способа, для создания оператора ссылки для захвата этих идентификаторов в качестве новых полей. Linq просто может это сделать. Лучшее, что вы можете сделать в этом случае заключается в следующем:

var ids = r.Select(x => x.Id).Distinct().OrderBy(x => x).ToArray(); 

var query = 
    from x in r 
    group x by x.DateTime into gxs 
    let lookup = gxs.ToLookup(x => x.Id, x => (int?)x.Value) 
    select new 
    { 
     DateTime = gxs.Key, 
     Values = ids.Select(i => new 
     { 
      Id = i, 
      Value = lookup[i].FirstOrDefault(), 
     }).ToArray(), 
    }; 

Это производит это:

result

Если Идентификаторы известны, то следующий вариант лучше:

var query = 
    from x in r 
    group x by x.DateTime into gxs 
    let lookup = gxs.ToLookup(x => x.Id, x => (int?)x.Value) 
    select new 
    { 
     DateTime = gxs.Key, 
     _1 = lookup[1].FirstOrDefault(), 
     _2 = lookup[2].FirstOrDefault(), 
     _3 = lookup[3].FirstOrDefault(), 
    }; 
+1

Привет, @Enigmativity, где этот снимок экрана? –

+2

@NikolayKostov - Я использую http://www.linqpad.net/ для запуска моего кода и создаю скриншоты из его вывода. – Enigmativity

+0

Это можно сделать с помощью Dynamic Linq во время выполнения. Мне удалось использовать его для запроса неизвестного количества поисковых запросов на неизвестном числе полей (как в этом примере ... вертикальный список полей, связанных с каждым пользователем, который должен быть перенесен в результирующий набор), возвращая неизвестный набор полей и упорядочение по неизвестному набору полей. Общий многопользовательский многопользовательский поиск. System.Linq.Dynamic. – Triynko