2015-05-14 106 views
1

我正嘗試使用Linq將List<Person>分組。Linq GroupBy具有動態屬性的匿名類型

var grouped = personList.GroupBy(x => new { x.Forename, x.Age }) 
         .Select(x => new { Description = x.Key, Count = x.Count() }); 

我該如何製作將被分組的屬性來自一個變量?

var groupByProperties = new string[] { "Forename", "Age" }; 
personList.GroupBy(x => new { ............ }) 
      .Select(x => new { Description = x.Key, Count = x.Count() }); 

groupByProperties將來自用戶輸入網頁上(<select multiple>)。

我不能完全理解ExpandoObjectdynamic的正確語法,並且不確定是否需要在此處使用反射。

Person類可能看起來像:

public class Person 
{ 
    public string Forename { get; set; } 
    public string Surname { get; set; } 
    public int Age { get; set; } 
    public string Gender { get; set; } 
} 

結果是通過對UI(網頁)爲JSON,從一個DataGrid將產生傳遞回來。我將使用JavaScript循環返回的Description對象,並從中生成網格。

+0

不要在LINQ使用ExpandoObject因爲這可能會導致內存泄漏 – dr4cul4

+2

目前尚不清楚你想怎麼這個是動態的 - 它仍然是一個編譯時的選擇呢?你需要*整個*組鍵作爲描述屬性嗎?之後你對結果做什麼? –

+2

@ dr4cul4:謹慎地闡述和/或提供參考/證據? –

回答

1

與感謝potehin143指着我對ScottGu出色的Linq Dynamic Query Library,我已經成功地得到的東西運行。

我已經結束了一個很好的單行(雖然語法稍微離奇)。

var fieldsToGroupBy = new string[] { "Forename", "Age" }; 

var grouped = personList.GroupBy("new ("+fieldsToGroupBy.ToCommaSeparatedString("it.")+")", "it") 
       .Select("new (it.Key as Description, it.Count() as Count)"); 

response.Data = (dynamic)grouped; 

ToCommaSeparatedString()是一個簡單的擴展方法來改變[ 「用名字」, 「年齡」]爲 「it.Forename,it.Age」。

以前的解決方案(下面)沒有以我期望的格式返回數據。 (這是返回所有數據在組中,而不是隻是一個總結。)信貸到Mitsu這個解決方案(博客文章herehere)。

var groupByProperties = new string[] { "Forename", "Age" }; 
var grouped = personList.GroupByMany(groupByProperties); 

Linq動態查詢庫做了太多的事情,甚至不能發佈一個片段。該GroupByMany方法:

public static IEnumerable<GroupResult> GroupByMany<TElement>(
     this IEnumerable<TElement> elements, params string[] groupSelectors) 
{ 
    var selectors = 
     new List<Func<TElement, object>>(groupSelectors.Length); 
    foreach (var selector in groupSelectors) 
    { 
     LambdaExpression l = 
      DynamicExpression.ParseLambda(
       typeof(TElement), typeof(object), selector); 
     selectors.Add((Func<TElement, object>)l.Compile()); 
    } 
    return elements.GroupByMany(selectors.ToArray()); 
} 

public static IEnumerable<GroupResult> GroupByMany<TElement>(
    this IEnumerable<TElement> elements, 
    params Func<TElement, object>[] groupSelectors) 
{ 
    if (groupSelectors.Length > 0) 
    { 
     var selector = groupSelectors.First(); 

     //reduce the list recursively until zero 
     var nextSelectors = groupSelectors.Skip(1).ToArray(); 
     return 
      elements.GroupBy(selector).Select(
       g => new GroupResult 
       { 
        Key = g.Key, 
        Count = g.Count(), 
        Items = g, 
        SubGroups = g.GroupByMany(nextSelectors) 
       }); 
    } 
    else 
     return null; 
} 
-1

試試這個

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication29 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<Person> personList = new List<Person>(); 
      string[] groups = { "Forename", "Surname" }; 
      var grouped = personList.GroupBy(x => new object[] { Grouper(x, groups) }) 
         .Select(x => new { Description = x.Key, Count = x.Count() }); 
     } 
     static object[] Grouper(Person person, string[] groups) 
     { 
      List<object> results = new List<object>(); 
      foreach (string group in groups) 
      { 
       switch (group) 
       { 
        case "Forename" : 
         results.Add(person.Forename); 
         break; 
        case "Surname": 
         results.Add(person.Surname); 
         break; 
        case "Age": 
         results.Add(person.Age); 
         break; 
        case "Gender": 
         results.Add(person.Gender); 
         break; 
       } 
      } 


      return results.ToArray(); 
     } 
    } 
    public class Person 
    { 
     public string Forename { get; set; } 
     public string Surname { get; set; } 
     public int Age { get; set; } 
     public string Gender { get; set; } 
    } 
} 
+0

'EqualityComparer .Default'將使用數組的引用作爲它的標識,而不是數組的值,所以使用這個解決方案,您分組的每個值都將是唯一的。 – Servy