如何在自引用linq中获得针对高度父级的极端叶节点

时间:2017-11-03 06:37:44

标签: c# linq

我有数据结构

-Emp1 - Emp1_1 - Emp1_1_1
               - Emp1_1_2
      - Emp1_2 - Emp1_2_1
               - Emp1_2_2
-Emp2 - Emp2_1 - Emp2_1_1
               - Emp2_1_2
      - Emp2_2 - Emp2_2_1
               - Emp2_2_2

我想要一个字典,它将极端叶节点作为键,其最高父节点作为值。 OP:

(Emp1_1_1,Emp1) (Emp1_1_2,Emp1) (Emp1_2_1,Emp1) (Emp1_2_2,Emp1) (Emp2_1_1,Emp2) (Emp2_1_2,Emp2) (Emp2_2_1,Emp2) (Emp2_2_2,Emp2)

(Emp1_1_1, Emp1)
(Emp1_1_2, Emp1) 
(Emp1_2_1, Emp1)
(Emp1_2_2, Emp1)
(Emp2_1_1, Emp2)
(Emp2_1_2, Emp2)
(Emp2_2_1, Emp2)
(Emp2_2_2, Emp2)

下面是c#代码

public class Program
    {
        public static void Main()
        {
            var program = new Program();
            var empList = program.GetData();
           //Some linq which return the expected dictionary.
            Console.WriteLine("Press any key to exit");
            Console.ReadKey();
        }

        public class Employee
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int parentEmployee { get; set; }
            public List<Employee> childList { get; set; }
        }

        List<Employee> GetData()
        {
            var empList = new List<Employee>();

            var emp1 = new Employee() { Id = 1, Name = "Emp1_Name", childList = new List<Employee>() };
            var emp1_1 = new Employee() { Id = 2, Name = "Emp1_1_Name", parentEmployee = emp1.Id, childList = new List<Employee>() };
            var emp1_2 = new Employee() { Id = 3, Name = "Emp1_2_Name", parentEmployee = emp1.Id, childList = new List<Employee>() };
            emp1.childList.Add(emp1_1);
            emp1.childList.Add(emp1_2);
            var emp1_1_1 = new Employee() { Id = 4, Name = "Emp1_1_1_Name", parentEmployee = emp1_1.Id };
            var emp1_1_2 = new Employee() { Id = 5, Name = "Emp1_1_2_Name", parentEmployee = emp1_1.Id };
            emp1_1.childList.Add(emp1_1_1);
            emp1_1.childList.Add(emp1_1_2);
            var emp1_2_1 = new Employee() { Id = 6, Name = "Emp1_2_1_Name", parentEmployee = emp1_2.Id };
            var emp1_2_2 = new Employee() { Id = 7, Name = "Emp1_2_2_Name", parentEmployee = emp1_2.Id };
            emp1_2.childList.Add(emp1_2_1);
            emp1_2.childList.Add(emp1_2_2);



            var emp2 = new Employee() { Id = 1, Name = "emp2_Name", childList = new List<Employee>() };
            var emp2_1 = new Employee() { Id = 2, Name = "emp2_1_Name", parentEmployee = emp2.Id, childList = new List<Employee>() };
            var emp2_2 = new Employee() { Id = 3, Name = "emp2_2_Name", parentEmployee = emp2.Id, childList = new List<Employee>() };
            emp2.childList.Add(emp2_1);
            emp2.childList.Add(emp2_2);
            var emp2_1_1 = new Employee() { Id = 4, Name = "emp2_1_1_Name", parentEmployee = emp2_1.Id };
            var emp2_1_2 = new Employee() { Id = 5, Name = "emp2_1_2_Name", parentEmployee = emp2_1.Id };
            emp2_1.childList.Add(emp2_1_1);
            emp2_1.childList.Add(emp2_1_2);
            var emp2_2_1 = new Employee() { Id = 6, Name = "emp2_2_1_Name", parentEmployee = emp2_2.Id };
            var emp2_2_2 = new Employee() { Id = 7, Name = "emp2_2_2_Name", parentEmployee = emp2_2.Id };
            emp2_2.childList.Add(emp2_2_1);
            emp2_2.childList.Add(emp2_2_2);

            empList.Add(emp1);
            empList.Add(emp2);
            return empList;
        }
    }

我尝试了一些解决方案,比如在linq中调用私有自引用功能, 但它适用于一个父母 - 一个孩子的关系。

2 个答案:

答案 0 :(得分:1)

如果可以使用递归函数:

        Func<IEnumerable<Employee>, IEnumerable<Employee>> flatten = null;
        flatten = (IEnumerable<Employee> employees) => 
            employees.SelectMany(c => c.childList != null ? flatten(c.childList) : Enumerable.Empty<Employee>()).Concat(employees);

        var dict = (
            from topNode in empList
                    from node in flatten(topNode.childList)
                    where node.childList == null || node.childList.Count == 0
                    select new KeyValuePair<string, string>(node.Name, topNode.Name)
            ).ToDictionary(kv => kv.Key, kv => kv.Value);


        foreach(var keyValuePair in dict)
        {
            Console.WriteLine($"Key={keyValuePair.Key}, Value={keyValuePair.Value}");
        }

输出:

Key=Emp1_1_1_Name, Value=Emp1_Name
Key=Emp1_1_2_Name, Value=Emp1_Name
Key=Emp1_2_1_Name, Value=Emp1_Name
Key=Emp1_2_2_Name, Value=Emp1_Name
Key=emp2_1_1_Name, Value=emp2_Name
Key=emp2_1_2_Name, Value=emp2_Name
Key=emp2_2_1_Name, Value=emp2_Name
Key=emp2_2_2_Name, Value=emp2_Name

答案 1 :(得分:0)

试试这个

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="a2msoft.app_one">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:name=".AppController"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name=".activiy.LoginActivity"
            android:label="@string/app_name"
            android:launchMode="singleTop"
            android:windowSoftInputMode="adjustPan">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".activiy.RegisterActivity"
            android:label="@string/app_name"
            android:launchMode="singleTop"
            android:windowSoftInputMode="adjustPan" />
        <activity
            android:name=".activiy.MainActivity"
            android:label="@string/app_name"
            android:launchMode="singleTop"
            android:theme="@style/AppTheme"
            >
        <meta-data
            android:name="android.app.default_searchable"
            android:value=".SearchResultsActivity" />
        </activity>
        <activity
            android:name=".activiy.ItemActivity"
            android:label="@string/app_name"
            android:launchMode="singleTop"

            android:parentActivityName=".activiy.MainActivity"


            />
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".activiy.MainActivity" />
    </application>

</manifest>

结果

public static void Main()
{
    var program = new Program();
    var empList = program.GetData();

    Func<IEnumerable<Employee>, Employee, Dictionary<Employee, Employee>> TreeToDict = null;
    TreeToDict = (employees, topParent) => 
    employees.SelectMany(e => 
                         {
                             if(e.childList != null)
                             {
                                 return TreeToDict(e.childList, topParent == null ? e : topParent);
                             }
                             else
                             {
                                 Dictionary<Employee, Employee> dict = new Dictionary<Employee, Employee>();
                                 dict.Add(e, topParent == null ? e : topParent);
                                 return dict;
                             }

                         }).ToDictionary(x => x.Key, x => x.Value);

    foreach(var emp in TreeToDict (empList, null))
    {
        Console.WriteLine("key : {0}, value {1}", emp.Key.Name, emp.Value.Name);
    }
}