Linq排除儿童中的列

时间:2016-02-08 00:34:19

标签: c# .net linq

我正在尝试以下方法:给定动态对象列表,使用提供的列列表执行GROUP BY。这是我到目前为止所做的:

using Newtonsoft.Json;

private static void Main(string[] args)
{
    dynamic[] data = {
        new { A = "A1", B = "B1", C = "C1", D = "D1", E = "E1", F = "F1"},
        new { A = "A1", B = "B1", C = "C1", D = "D1", E = "E1", F = "F1", G = "G1"},
        new { A = "A1", B = "B1", C = "C1", D = "D1", E = "E1", H = "H1", I = "I1"}
    };

    var newList = data.GroupBy(row => new { row.A, row.B, row.C, row.D, row.E })
        .Select(
            y =>
                new
                {
                    A = y.Key.A, B = y.Key.B, C = y.Key.C, D = y.Key.D, E = y.Key.E,
                    Children = y.ToList()
                });

    var str = JsonConvert.SerializeObject(newList);

    Console.Read();
}

这符合我的需要。但是,我想删除一些显示为Children字段一部分的其他列。这是我现在为str获得的输出:

[
   {
      "A":"A1",
      "B":"B1",
      "C":"C1",
      "D":"D1",
      "E":"E1",
      "Children":[
         {
            "A":"A1",
            "B":"B1",
            "C":"C1",
            "D":"D1",
            "E":"E1",
            "F":"F1"
         },
         {
            "A":"A1",
            "B":"B1",
            "C":"C1",
            "D":"D1",
            "E":"E1",
            "F":"F1",
            "G":"G1"
         },
         {
            "A":"A1",
            "B":"B1",
            "C":"C1",
            "D":"D1",
            "E":"E1",
            "H":"H1",
            "I":"I1"
         }
      ]
   }
]

我理想的是以下内容:

[
   {
      "A":"A1",
      "B":"B1",
      "C":"C1",
      "D":"D1",
      "E":"E1",
      "Children":[
         {
            "E":"E1",
            "F":"F1"
         },
         {
            "F":"F1",
            "G":"G1"
         },
         {
            "H":"H1",
            "I":"I1"
         }
      ]
   }
]

有关如何实现这一目标的任何建议?我所知道的是,对象中可能存在一定数量的字段(例如,A,B,C,D,E),但是无法控制其他字段(例如,F,G,H等)< / p>

1 个答案:

答案 0 :(得分:1)

您可以使用ExpandoObject类仅存储每个项目唯一的属性和反射来选择这些唯一属性。

这就是为什么我设法在LinqPad中划伤:

dynamic[] data =
{
    new { A = "A1", B = "B1", C = "C1", D = "D1", E = "E1", F = "F1" },
    new { A = "A1", B = "B1", C = "C1", D = "D1", E = "E1", F = "F1", G = "G1" },
    new { A = "A1", B = "B1", C = "C1", D = "D1", E = "E1", H = "H1", I = "I1" }
};

var keyProperties = new[] { "A", "B", "C", "D", "E" };
var newList = data.GroupBy(row => new { row.A, row.B, row.C, row.D, row.E }).Select(
    y => new
         {
             A = y.Key.A,
             B = y.Key.B,
             C = y.Key.C,
             D = y.Key.D,
             E = y.Key.E,
             Children = y.Select(
                 item =>
                 {
                     IEnumerable<dynamic> itemProps = item.GetType().GetProperties();
                     List<dynamic> properties =
                         itemProps.Where(p => !Enumerable.Contains(keyProperties, p.Name)).ToList();
                     var result = new ExpandoObject();
                     foreach (var property in properties)
                     {
                         var value = property.GetValue(item, null);
                         if (value != null)
                         {
                             ((IDictionary<string, object>)result).Add(property.Name, value);
                         }
                     }
                     return result;
                 }).ToList()
         });
var str = JsonConvert.SerializeObject(newList);

结果是:

[
  {
    "A": "A1",
    "B": "B1",
    "C": "C1",
    "D": "D1",
    "E": "E1",
    "Children": [
      {
        "F": "F1"
      },
      {
        "F": "F1",
        "G": "G1"
      },
      {
        "H": "H1",
        "I": "I1"
      }
    ]
  }
]

修改

要合并子级别的元素,您需要稍微更改投影。

首先,Select变为SelectMany以返回KeyValuePair<string, object>的集合,随后将按名称分组并连接成数组:

Children = y.SelectMany(item =>
{
    IEnumerable<dynamic> itemProps = item.GetType().GetProperties();
    List<dynamic> properties = itemProps.Where(p => !Enumerable.Contains(keyProperties,p.Name)).ToList();
    var result = new ExpandoObject();
    foreach(var property in properties)
    {
        var value = property.GetValue(item, null);
        if(value != null)
            ((IDictionary<string, object>)result).Add(property.Name, value);
    }
    return (IDictionary<string, object>)result;
}).GroupBy(prop => prop.Key, prop => prop.Value)
.Select(g => 
{
    var result = new ExpandoObject();
    ((IDictionary<string, object>)result).Add(g.Key, g.ToArray());
    return result;
})
.ToList()

这不是最优雅的代码,但它应该完成工作。