UPDATE: Utworzono następującą metodę ogólną, które można zbudować stół obrotowy z każdej kolekcji
public static DataTable ToPivotTable<T, TColumn, TRow, TData>(
this IEnumerable<T> source,
Func<T, TColumn> columnSelector,
Expression<Func<T, TRow>> rowSelector,
Func<IEnumerable<T>, TData> dataSelector)
{
DataTable table = new DataTable();
var rowName = ((MemberExpression)rowSelector.Body).Member.Name;
table.Columns.Add(new DataColumn(rowName));
var columns = source.Select(columnSelector).Distinct();
foreach (var column in columns)
table.Columns.Add(new DataColumn(column.ToString()));
var rows = source.GroupBy(rowSelector.Compile())
.Select(rowGroup => new {
Key = rowGroup.Key,
Values = columns.GroupJoin(
rowGroup,
c => c,
r => columnSelector(r),
(c, columnGroup) => dataSelector(columnGroup))
});
foreach (var row in rows) {
var dataRow = table.NewRow();
var items = row.Values.Cast<object>().ToList();
items.Insert(0, row.Key);
dataRow.ItemArray = items.ToArray();
table.Rows.Add(dataRow);
}
return table;
}
Zastosowanie:
var table = Languagemaster.ToPivotTable(
item => item.language,
item => item.keyName,
items => items.Any() ? items.First().keyValue : null);
ma trzy parametry:
- kolumnę selektor właściwości, który wybiera kolumny (tj. co będzie w nagłówkach kolumn) w twoim przypadku są to różne wartości języków, ale może to być cokolwiek innego, jak data.
- selektor właściwości wiersza - jest wartością, która pojawi się w nagłówkach wierszy, z której każdy wiersz będzie powiązany. Pamiętaj - to wyrażenie, a nie zwykły delegat. Potrzebujemy go, aby ustawić nazwę kolumny pierwszej kolumny.
- selektor danych - jest to metoda, która będzie uruchamiana na zgrupowanych danych dla każdej komórki. To znaczy. w twoim przypadku po prostu wybieramy
keyValue
właściwość pierwszego elementu w grupie. Ale mogą to być przedmioty o numerach items => items.Count()
lub cokolwiek innego.
Wynik:
ORIGINAL ODPOWIEDŹ:
To zapytanie zwróci pivot dla Twoich danych. Każda pozycja w zapytaniu będzie miał Name
(czyli „Miasto” w przykładzie) oraz listę wartości - wartość dla każdej kolumny obrotu (czyli dla każdego języka będziemy mieć wartość zawierającą nazwę języka jako Column
i Value
)
var languages = Languagemaster.Select(x => x.language).Distinct();
var query = from r in Languagemaster
group r by r.keyName into nameGroup
select new {
Name = nameGroup.Key,
Values = from lang in languages
join ng in nameGroup
on lang equals ng.language into languageGroup
select new {
Column = lang,
Value = languageGroup.Any() ?
languageGroup.First().keyValue : null
}
};
Jak zbudować tabelę danych z tego zapytania
DataTable table = new DataTable();
table.Columns.Add("keyName"); // first column
foreach (var language in languages)
table.Columns.Add(language); // columns for each language
foreach (var key in query)
{
var row = table.NewRow();
var items = key.Values.Select(v => v.Value).ToList(); // data for columns
items.Insert(0, key.Name); // data for first column
row.ItemArray = items.ToArray();
table.Rows.Add(row);
}
możliwe duplikat [LINQ swapowych kolumn na wiersze] (http://stackoverflow.com/questions/6950495/linq-swap-columns-into-rows) – Fals
wygląda tak jak chcesz grupować kolumny według wartości 'keyName'. – YD1m