使用 LINQ 标准化数据

发布于 2024-08-23 08:41:22 字数 687 浏览 1 评论 0原文

假设我们有一些非规范化数据,如下所示:

List<string[]> dataSource = new List<string[]>();
string [] row1 = {"grandParentTitle1", "parentTitle1", "childTitle1"}; 
string [] row2 = {"grandParentTitle1", "parentTitle1", "childTitle2"};
string [] row3 = {"grandParentTitle1", "parentTitle2", "childTitle3"};
string [] row4 = {"grandParentTitle1", "parentTitle2", "childTitle4"};
dataSource.Add(row1);

我需要对其进行规范化,例如获得 IEnumerable<儿童>填充了 Child.Parent 和 Child.Parent.GrandParent。

命令式的方式或多或少是明确的。使用 Linq 会更短吗?

在一个查询中效果更好,并且这应该可以扩展到更多实体。

我尝试过单独创建 IEnumerable< GrandParent >,然后 IEnumerable<父>与分配等。

请提示这可以通过功能方式实现吗?

Assume we have some denormalized data, like this:

List<string[]> dataSource = new List<string[]>();
string [] row1 = {"grandParentTitle1", "parentTitle1", "childTitle1"}; 
string [] row2 = {"grandParentTitle1", "parentTitle1", "childTitle2"};
string [] row3 = {"grandParentTitle1", "parentTitle2", "childTitle3"};
string [] row4 = {"grandParentTitle1", "parentTitle2", "childTitle4"};
dataSource.Add(row1);

I need to normalize it, e.g. to get IEnumerable< Child > with Child.Parent and Child.Parent.GrandParent filled.

Imperative way is more or less clear. Will it be shorter with Linq?

Better in one query, and this should be expandable for more entities.

I tried something like separately create IEnumerable< GrandParent >, then IEnumerable< Parent > with assigning etc.

PLease make a hint could this be achieved in a functional way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蝶…霜飞 2024-08-30 08:41:22

您可以使用 group by 完全执行您想要的操作。不幸的是,我对 C# LINQ 语法的了解有限,所以我只能向您展示调用扩展方法 GroupBy 的方法。

var normalized = dataSource
    .GroupBy(source => source[0], (grandParent, grandParentChilds) => new { GrandParent = grandParent, Parents = grandParentChilds
        .GroupBy(source => source[1], (parent, parentChilds) => new { Parent = parent, Children = from source in parentChilds select source[2]}) });

foreach (var grandParent in normalized)
{
    Console.WriteLine("GrandParent: {0}", grandParent.GrandParent);
    foreach (var parent in grandParent.Parents)
    {
        Console.WriteLine("\tParent: {0}", parent.Parent);
        foreach (string child in parent.Children)
            Console.WriteLine("\t\tChild: {0}", child);
    }
}

You can do exactly what you want using group by. Unfortunately my knowledge of the C# LINQ syntax is limited, so I just can show you the way calling extension method GroupBy.

var normalized = dataSource
    .GroupBy(source => source[0], (grandParent, grandParentChilds) => new { GrandParent = grandParent, Parents = grandParentChilds
        .GroupBy(source => source[1], (parent, parentChilds) => new { Parent = parent, Children = from source in parentChilds select source[2]}) });

foreach (var grandParent in normalized)
{
    Console.WriteLine("GrandParent: {0}", grandParent.GrandParent);
    foreach (var parent in grandParent.Parents)
    {
        Console.WriteLine("\tParent: {0}", parent.Parent);
        foreach (string child in parent.Children)
            Console.WriteLine("\t\tChild: {0}", child);
    }
}
浅语花开 2024-08-30 08:41:22

Linq 确实做了相反的事情。 IE。如果你将其标准化,你可以很容易地说

from g in grandParents
from p in g.Parents
from c in p.Children
select new { GrandParentName = g.Name, ParentName = p.Name, ChildName = c.Name };

“做你所要求的事情更棘手”。像这样的东西

var grandparents = (from g in dataSource
                    select new GrandParent {
                        Title = g[0],
                        Parents = (from p in dataSource
                                   where p[0] == g[0]
                                   select new Parent {
                                      Title = p[1],
                                      Children = from c in dataSource
                                                 where p[1] == c[1]
                                                 select new
                                                            {
                                                                Title = c[2]
                                                            }
                                   }).Distinct(new ParentTitleComparer())
                    }).Distinct(new GrandParentTitleComparer());

我不相信这比命令式版本读起来更好。

Linq really does the opposite of this. ie. If you had it normalised, you could easily say

from g in grandParents
from p in g.Parents
from c in p.Children
select new { GrandParentName = g.Name, ParentName = p.Name, ChildName = c.Name };

To do what you're asking is more tricky. Something like this

var grandparents = (from g in dataSource
                    select new GrandParent {
                        Title = g[0],
                        Parents = (from p in dataSource
                                   where p[0] == g[0]
                                   select new Parent {
                                      Title = p[1],
                                      Children = from c in dataSource
                                                 where p[1] == c[1]
                                                 select new
                                                            {
                                                                Title = c[2]
                                                            }
                                   }).Distinct(new ParentTitleComparer())
                    }).Distinct(new GrandParentTitleComparer());

I'm not convinced this reads better than the imperative version would.

蓝眼泪 2024-08-30 08:41:22

最基本的方法是使用匿名变量:

from ds0 in dataSource group ds0 by ds0[0] into grandparents
select new
{
    Grandparent = grandparents.Key,
    Parents =
        from ds1 in grandparents group ds1 by ds1[1] into parents
        select new
        {
            Parent = parents.Key, 
            Children = from ds2 in parents select ds2[2]
        }
};

如果您想使用具体类来执行此操作,我建议创建一个 Person 类,其构造函数采用 IEnumerable< /code> 代表正在构造的 Person 的子级。然后您可以这样做:

from ds0 in dataSource
group ds0 by ds0[0] into grandparents
select new Person(grandparents.Key,
    from ds1 in grandparents
    group ds1 by ds1[1] into parents
    select new Person(parents.Key,
        from ds2 in parents
        select new Person(ds2[2])));

这些解决方案对您有用吗?

如果您想要不同的 GrandParentParentChild 类型,那么您应该能够修改最后一个示例以适应。

The most basic way of doing this would be with anonymous variables:

from ds0 in dataSource group ds0 by ds0[0] into grandparents
select new
{
    Grandparent = grandparents.Key,
    Parents =
        from ds1 in grandparents group ds1 by ds1[1] into parents
        select new
        {
            Parent = parents.Key, 
            Children = from ds2 in parents select ds2[2]
        }
};

If you wanted to do this with concrete classes I would suggest creating a Person class with a constructor that takes an IEnumerable<Person> representing the children of the Person being constructed. Then you could do this:

from ds0 in dataSource
group ds0 by ds0[0] into grandparents
select new Person(grandparents.Key,
    from ds1 in grandparents
    group ds1 by ds1[1] into parents
    select new Person(parents.Key,
        from ds2 in parents
        select new Person(ds2[2])));

Do either of these solutions work for you?

If you want different GrandParent, Parent & Child types then you should be able to modify the last example to suit.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文