GroupBy Linq结果的多个Groupby

时间:2017-04-22 09:57:12

标签: c# linq grouping

我有两个课程可以说

class Foo
{
 List<Bar> Bars{get;set;} 
}

class Bar
{
  string Name{get;set;}
  string Value{get;set;}
}

我有这样的查询

var resultsGroupedByState=Foos.GroupBy(x=>x.Bars.First(c=>c.Name=="state").Value);

将返回按州分组的结果,而且用户可以按字段定义组的层次结构,例如

  1. groupBy State
  2. groupBy County
  3. groupBy City等
  4. 我要做多少级别的小组,我不知道。我要在层次结构中首先定义一个groupby,然后在第一个groupby的结果的基础上进行基于第二个值的groupby,并继续。

    最后我要从这些数据中生成一个xml。

    <State value="anyState">
       <County value="anyCounty">
           <City value="anyCity">
              ..........
            </City>
        </County>
     </State>
    

2 个答案:

答案 0 :(得分:1)

基本上你需要生成XML。一种解决方案可以是递归执行GroupBy并直接创建XMLDocument

这是一个可以做到这一点的助手类。

public class XmlGenerator
{
    private XmlDocument _document;
    private List<string> _fields;
    private int index = 0;

    public XmlGenerator(List<string> fields)
    {
        _fields = fields;
    }

    public void GenerateXML(IEnumerable<Foo> lookupData, XmlElement root, string field)
    {
        var fieldGrouping = lookupData.GroupBy(v => v.Bars.First(x => x.Name == field).Value);
        foreach (var grouping in fieldGrouping)
        {
            var element = _document.CreateElement(field);
            var attrib = _document.CreateAttribute("value");
            attrib.InnerText = grouping.Key;

            element.Attributes.Append(attrib);
            root.AppendChild(element);

            // If that is last field. No need to do any grouping.
            if (index < _fields.Count - 1)
            {
                // After each nested call update the nested level.
                // If GenerateXML do another that will be upon next nested level
                index += 1;
                GenerateXML(grouping, element, _fields[index]);
                index -= 1;
                // Make sure to change back nested level index otherwise that will not works if you have multiple groups.
            }
        }
    }

    public string GenerateXML(IEnumerable<Foo> lookupData)
    {
        _document = new XmlDocument();
        var root = _document.CreateElement("Root");
        _document.AppendChild(root);
        index = 0;

        GenerateXML(lookupData, root, _fields[index]);

        return _document.OuterXml;
    }
}

我在这里做的实际上是,我已经在List<string>.内存储了所有字段列表并编写了一个按特定字段分组的辅助方法。每次传递时,我都会传递需要分组的方法数据和要分组的字段名称。

希望如此,这解决了你的问题。

答案 1 :(得分:-1)

你不需要GrroupBy。试试这个

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

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
           string xml =
               "<Root>" +
                    "<State value=\"AState\">" +
                       "<County value=\"ACounty\">" +
                           "<City value=\"ACity\"/>" +
                           "<City value=\"BCity\"/>" +
                           "<City value=\"CCity\"/>" +
                        "</County>" +
                       "<County value=\"BCounty\">" +
                           "<City value=\"ACity\"/>" +
                           "<City value=\"BCity\"/>" +
                           "<City value=\"CCity\"/>" +
                        "</County>" +
                       "<County value=\"CCounty\">" +
                           "<City value=\"ACity\"/>" +
                           "<City value=\"BCity\"/>" +
                           "<City value=\"CCity\"/>" +
                        "</County>" +
                     "</State>" +
                    "<State value=\"BState\">" +
                       "<County value=\"ACounty\">" +
                           "<City value=\"ACity\"/>" +
                           "<City value=\"BCity\"/>" +
                           "<City value=\"CCity\"/>" +
                        "</County>" +
                       "<County value=\"BCounty\">" +
                           "<City value=\"ACity\"/>" +
                           "<City value=\"BCity\"/>" +
                           "<City value=\"CCity\"/>" +
                        "</County>" +
                       "<County value=\"CCounty\">" +
                           "<City value=\"ACity\"/>" +
                           "<City value=\"BCity\"/>" +
                           "<City value=\"CCity\"/>" +
                        "</County>" +
                     "</State>" +
                     "<State value=\"CState\">" +
                       "<County value=\"ACounty\">" +
                           "<City value=\"ACity\"/>" +
                           "<City value=\"BCity\"/>" +
                           "<City value=\"CCity\"/>" +
                        "</County>" +
                       "<County value=\"BCounty\">" +
                           "<City value=\"ACity\"/>" +
                           "<City value=\"BCity\"/>" +
                           "<City value=\"CCity\"/>" +
                        "</County>" +
                       "<County value=\"CCounty\">" +
                           "<City value=\"ACity\"/>" +
                           "<City value=\"BCity\"/>" +
                           "<City value=\"CCity\"/>" +
                        "</County>" +
                     "</State>" +
                    "</Root>";

           XElement root = XElement.Parse(xml);

           List<Foo> foos = Helper(root); 

        }
        public static List<Foo> Helper(XElement element)
        {
            if (element.HasElements)
            {
                string tagName = ((XElement)element.FirstNode).Name.LocalName;

                List<Foo> children = element.Elements(tagName).Select(x => new Foo()
                {
                    Name = tagName,
                    Value = (string)x.Attribute("value"),
                    foos = Helper(x)
                }).ToList();


                return children;
            }
            else
            {
                return null;
            }
        }
    }
    public class Foo
    {
        public string Name { get; set; }
        public string Value { get; set; }

        public List<Foo> foos { get; set; }
    }

}