【问题标题】:How to flatten self referencing query?如何展平自引用查询?
【发布时间】:2016-10-16 19:24:37
【问题描述】:

似乎这是已经回答但我找不到的那种事情。
我有下表:

Id     Parent     Text
-----------------------
1      NULL       A
2       1         B
3       2         C
4       3         D
5      NULL       E
6       5         F
7       6         G

现在我想要这样的结果:(List<string>)

A
A > B
A > B > C
A > B > C > D
E
E > F
E > F > G

但问题是,我正在做的这个项目,首先使用数据库,我的意思是没有导航属性,Parent 的类型是string 而不是IEnumerable<T>

到目前为止我做了什么:

var list = new List<string>();
string e2 = string.Empty;
foreach (var item in query)
{
    string e1 = string.Empty;
    if (item.Parent == null)
    {
        list.Add(p.Text);
        e2 = item.Text;
    }
    else
    {
        foreach (var subItem in query.Where(t => t.Id == p.Parent))
        {
            if (subItem.Id != 1)
            {
                e1 = e2 + " > " + subItem.Text;
            }
            else
            {
                e1 = subItem.Text;
            }
        }
        list.Add(e1 + " > " + p.Text);
    }
}

【问题讨论】:

  • 显示query变量的定义
  • 这只是一个简单的 linq 查询:var query = from item in myTable select item;
  • 查询是IQueryable&lt;T&gt;还是IEnumerable&lt;T&gt;会有很大的不同。在第一种情况下,您将执行 N 个数据库查询。在第二种情况下,您接受的朴素算法将进行 N * N 次搜索。换句话说,两者都将非常低效。无论如何,问题都是你的:)

标签: c# linq


【解决方案1】:

使用递归算法

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

namespace ConsoleApplication1
{
    class Program
    {
        static List<string> list = new List<string>();
        static DataTable dt = new DataTable();
        static void Main(string[] args)
        {
            dt.Columns.Add("Id", typeof(int));
            dt.Columns.Add("Parent", typeof(int));
            dt.Columns["Parent"].AllowDBNull = true;
            dt.Columns.Add("Text", typeof(string));

            dt.Rows.Add(new object[] {1, null, "A"});
            dt.Rows.Add(new object[] {2, 1, "B"});
            dt.Rows.Add(new object[] {3, 2, "C"});
            dt.Rows.Add(new object[] {4, 3, "D"});
            dt.Rows.Add(new object[] {5, null, "E"});
            dt.Rows.Add(new object[] {6, 5, "F"});
            dt.Rows.Add(new object[] {7, 6, "G"});

            GetRecursiveChildren(null, new List<string>());

            foreach (string row in list)
            {
                Console.WriteLine(row);
            }
            Console.ReadLine();
        }
        static void GetRecursiveChildren(int? parent, List<string> parents)
        {
            foreach (DataRow row in dt.AsEnumerable().Where(x => x.Field<int?>("Parent") == parent))
            {
                string text = row.Field<string>("Text");
                List<string> newParents = new List<string>();
                newParents.AddRange(parents);
                newParents.Add(text);
                list.Add(string.Join(" > ",newParents));
                int child = row.Field<int>("Id");
                GetRecursiveChildren(child, newParents);
            }
        }
    }

}

【讨论】:

    【解决方案2】:

    这对我有用:

    var source = new []
    {
        new { Id = 1, Parent = (int?)null, Text = "A" },
        new { Id = 2, Parent = (int?)1, Text = "B" },
        new { Id = 3, Parent = (int?)2, Text = "C" },
        new { Id = 4, Parent = (int?)3, Text = "D" },
        new { Id = 5, Parent = (int?)null, Text = "E" },
        new { Id = 6, Parent = (int?)5, Text = "F" },
        new { Id = 7, Parent = (int?)6, Text = "G" }
    };
    
    var lookup = source.ToLookup(x => x.Parent);
    
    Func<int?, IEnumerable<string>> recurse = null;
    recurse = p =>
        lookup[p].SelectMany(x => new [] { x.Text }
            .Concat(recurse(x.Id).Select(y => $"{x.Text} > {y}")));
    
    foreach (string x in recurse(null))
    {
        Console.WriteLine(x);
    }
    

    我明白了:

    一个 A > B A > B > C A > B > C > D 乙 E > F E > F > G

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-15
      • 2022-08-19
      • 1970-01-01
      相关资源
      最近更新 更多