使用LINQ取消数据结构

时间:2014-03-25 22:49:19

标签: c# linq

这不是一个家庭作业问题。如有必要,请随时推荐一个更好的地方发布。

鉴于以下数据结构:

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; }
}

以下数据:

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" },
};

将LINQiest重新塑造成如下所示的List的方法是什么:

First = "", Group = Sams
    First = Alex, Group = Sams
    First = John, Group = Sams
First = Sue, Group = Freds

有些注意事项:

  • 请注意, Thing 可以包含一系列内容。
  • 如果未指定第一,则假定为父项,并且包含第一且具有相同的所有记录均为子项
  • 根据上述规则,没有父母的记录被视为父母。

此示例显示了所需的结果:

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() });

3 个答案:

答案 0 :(得分:2)

这似乎很不错:

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();

这基本上忽略了First == ""的所有现有事物,然后按Group对所有剩余事物进行分组。然后,它会使用新父级重建列表,其中组具有多个内容。


在有“没有子女”的“父”对象的情况下,这是另一种更强大的选择:

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();

答案 1 :(得分:0)

功能无需错误检查或其他考虑因素。

    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());
            }
        }
    }

答案 2 :(得分:0)

一个陈述是......由于多个枚举而更有效率......

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(),
    };
}