C# 使用LINQ取消数据结构的平台化

C# 使用LINQ取消数据结构的平台化,c#,linq,C#,Linq,这不是一个家庭作业问题。如果需要的话,请随意推荐一个更好的地方来发布 鉴于以下数据结构: class Thing { public Thing() { this.Things = new List<Thing>(); } public string First { get; set; } public string Group { get; set; } public List<Thing> Thing

这不是一个家庭作业问题。如果需要的话,请随意推荐一个更好的地方来发布

鉴于以下数据结构:

class Thing
{
    public Thing() 
    {
        this.Things = new List<Thing>();
    }
    public string First { get; set; }

    public string Group { get; set; }

    public List<Thing> Things { get; set; }
}
需要注意的一些事项:

  • 请注意,事物可以包含事物列表
  • 如果未指定First,则假定为父项,并且包含具有相同组的First的所有记录都是子项
  • 根据上述规则,没有父项的记录被视为父项
此示例显示了所需的结果:

var result = data.Where(p => p.First == "").Select(p => 
{
    p.Things = data.Where(f => f.Group == p.Group).ToList();
    return p;
}).ToList();

result.AddRange(data.Except(result.SelectMany(f => f.Things)).ToList());
这也达到了预期的效果,但感觉有点长

var result = data
    .GroupBy(p => p.Group)
    .SelectMany(p => p.Where(f => f.First == "" || p.Count() == 1))
    .Select(p => new Thing { First = p.First, Group = p.Group, Things = data
        .Where(f => f.Group == p.Group && f.First != "" && p.First != f.First).ToList() });

没有错误检查或其他考虑的功能

    static void Main(string[] args)
    {
        var data = new List<Thing> { new Thing { First = "Alex", Group = "Sams" }, new Thing { First = "John", Group = "Sams" }, new Thing { First = "", Group = "Sams" }, new Thing { First = "Sue", Group = "Freds" } };

        var results = from item in data
                      group item by item.Group into g
                      select g;

        List<Thing> list = new List<Thing>();
        foreach (var item in results)
        {
            if (item.Count() > 1)
            {
                Thing parent = item.Where(x => String.IsNullOrEmpty(x.First)).First();
                parent.First = "";
                parent.Group = item.First().Group;
                parent.Things = item.Where(x => x != parent).ToList();
                list.Add(parent);
            }
            else
            {
                list.Add(item.First());
            }
        }
    }
static void Main(字符串[]args)
{
var data=new List{new Thing{First=“Alex”,Group=“Sams”},new Thing{First=“John”,Group=“Sams”},new Thing{First=”,Group=“Sams”},new Thing{First=“Sue”,Group=“Freds”};
var结果=来自数据中的项
逐项分组。分组为g
选择g;
列表=新列表();
foreach(结果中的var项目)
{
如果(item.Count()>1)
{
Thing parent=item.Where(x=>String.IsNullOrEmpty(x.First)).First();
父项。第一个=”;
parent.Group=item.First().Group;
parent.Things=item.Where(x=>x!=parent.ToList();
列表。添加(父级);
}
其他的
{
list.Add(item.First());
}
}
}

一句话是。。。由于有多个枚举,所以效率更高

var unflattenedList = data.GroupBy(thing => thing.Group, thing => thing, 
    (key, things) => new Thing()
    {
        First = things.Count() == 1 ? things.First().First : string.Empty, 
        Group = key,
        Things = things.Count() == 1 ? null : 
                     things.Where(t => t.First != string.Empty).ToList(),
    });
编辑: 然而,以下是我将使用的内容。。因为这消除了上述解决方案的多重枚举问题

你的LINQ是这样的

var unflattenedList = data.GroupBy(thing => thing.Group, thing => thing, GetThing);
您返回新事物的方法在这里

private static Thing GetThing(string key, IEnumerable<Thing> things)
{
    var thingList = things.ToList();
    return new Thing()
    {
        First = thingList.Count() == 1 ? thingList.First().First : string.Empty, 
        Group = key,
        Things = thingList.Count() == 1 ? null : 
                        thingList.Where(t => t.First != string.Empty).ToList(),
    };
}
私有静态对象获取(字符串键、IEnumerable对象)
{
var thingList=things.ToList();
返回新事物()
{
First=thingList.Count()==1?thingList.First()。First:string.Empty,
组=键,
Things=thingList.Count()==1?空:
thingList.Where(t=>t.First!=string.Empty).ToList(),
};
}

这似乎很好:

var result =
    data
        .Where(p => p.First != "")
        .GroupBy(p => p.Group)
        .Select(gps =>
            gps.Count() == 1
            ? gps.First()
            : new Thing()
            {
                First = "",
                Group = gps.Key,
                Things = gps.ToList(),
            })
        .ToList();
这基本上会忽略所有先有
的现有内容==”
,然后按
组对所有剩余内容进行分组。然后,它用一个新的父对象重新构建列表,其中组具有多个内容


在存在没有子对象的“父”对象的情况下,这里有一个更健壮的替代方案:

var result2 =
    data
        .GroupBy(p => p.Group)
        .Select(gps =>
            gps.Count() == 1
            ? gps.First()
            : new Thing()
            {
                First = "",
                Group = gps.Key,
                Things =
                    gps
                        .Where(p => p.First != "")
                        .ToList(),
            })
        .ToList();

只有一个层次还是多个层次的东西?好吧,父母和孩子,但没有比这更深的东西。是的,我尝试了很多东西,但它会填满很多页面,只是炫耀我的其他尝试。我知道有一百种方法可以做到这一点。。只是好奇其他人认为什么是最好的方式。你怎么能期望一个列表像那样缩进?我不确定输出格式是什么?它们是对象还是文本输出?您应该至少显示一个失败的尝试。一些你认为是你最好的尝试。这有助于我们回答这个问题。这不符合要求,因为它将父Sams行作为自身的子行包含在内。所以Sams的父级应该只有两个子级,这就解决了这个问题。这与我在OP中的最后一个示例在输出方面的最大区别是,Freds行包含一个空的子集合。没什么大不了的,真的。你和我的个人偏好是什么?都不是。。。我会写一个小方法,把小组变成一个新的东西()这也很有效,而且非常聪明。跳出框框思考得很好。+1做得好。我原以为这会导致groupby IEnumerable的多次枚举,但R#不这么认为,而且我想不出一种方法来测试它是否会。使用GroupBy selectResults函数肯定可以。@Kevin-谢谢。:-)什么是R#?
var result =
    data
        .Where(p => p.First != "")
        .GroupBy(p => p.Group)
        .Select(gps =>
            gps.Count() == 1
            ? gps.First()
            : new Thing()
            {
                First = "",
                Group = gps.Key,
                Things = gps.ToList(),
            })
        .ToList();
var result2 =
    data
        .GroupBy(p => p.Group)
        .Select(gps =>
            gps.Count() == 1
            ? gps.First()
            : new Thing()
            {
                First = "",
                Group = gps.Key,
                Things =
                    gps
                        .Where(p => p.First != "")
                        .ToList(),
            })
        .ToList();