簡體   English   中英

C#使用LINQ將帶有嵌套列表的兩個列表合並為一個

[英]C# Combine two lists with nested lists into one using LINQ

我在c#中有兩個以下結構列表。 <>中的每個名稱都是一個列表。 我想將這兩個列表合並到一個List<Server> 以下偽代碼顯示兩個這樣的列表以及結果應如何:

<Servers>                           <Servers>
+...                                +...
+-- Server A,1                      +-- Server A,1
|       +...                        |       +...    
|       +--<Maps>                   |       +--<Maps>
|           +--Map x                |           +--Map x
|               +...                |               +...    
|               +--<Times>          |               +--<Times>
|                   +--Time i       |                   +--Time l
|                   +--Time j       |               +--<Jumps>
|               +--<Jumps>          |                   +--Jump t
|                   +--Jump s       |                   +--Jump u
|           +--Map y                |           +--Map z
|               +...                |               +...
|               +--<Times>          |               +--<Jumps>  
|                   +-- Time k      |                   +--Jump v
+-- Server B,1                      +-- Server B,2

結果應該是:

<Servers>
+...
+-- Server A,1
|   +...
|   +--<Maps>
|       +-- Map x
|           +...
|           +--<Times>
|               +--Time i
|               +--Time j
|               +--Time l
|           +--<Jumps>
|               +--Jump s
|               +--Jump t
|               +--Jump u
|       +-- Map y
|           +...
|           +--<Times>
|               +--Time k
|       +-- Map z
|           +...
|           +--<Jumps>
|               +--Jump v
+-- Server B,1
+-- Server B,2

我嘗試使用linq的完全外連接,但結果也不是我想要的,因為我不理解具有相同密鑰的服務器不匹配,所以我總是有相同服務器的重復數據。 那是我停止嘗試使用linq並且只是使用循環手動合並列表的時候。

下面的代碼為我提供了所需的結果列表。 現在我將使用它,直到找到更好的方法。 使用linq是否有簡單/更短的方式? 使用lambda表達式?

  foreach (Server importServer in oImportList)
        {
            if (!CoreList.Contains(importServer))
            {
                CoreList.Add(importServer);
                continue;
            }

            Server coreServer = CoreList.FirstOrDefault(o => o.Equals(importServer));
            coreServer.Name = importServer.Name;
            coreServer.KZTimerVersion = importServer.KZTimerVersion;
            foreach(Map importMap in importServer.Maps)
            {
                if (!coreServer.Maps.Contains(importMap))
                {
                    coreServer.Maps.Add(importMap);
                    continue;
                }
                Map coreMap = coreServer.Maps.FirstOrDefault(o => o.Equals(importMap));
                coreMap.Jumps.Concat(importMap.Jumps);
                coreMap.Times.Concat(importMap.Times);
            }
        }

您可能一直在尋找.Union ,但這並不涉及嵌套列表,因此我認為這不是您真正需要的。 我設置了一個完整的例子 - 雖然結構與你的結構不一樣,但我認為你可以很容易地應用核心linq:

using System;
using System.Collections.Generic;
using System.Linq;

public class Map
{
    public string Name { get; set; }
    public IEnumerable<MapProperty> Properties { get; set; }
}

public class MapProperty
{
    public string Name { get; set; }
}

public class Test
{
    public static IEnumerable<Map> Merge(IEnumerable<Map> a, IEnumerable<Map> b)
    {
        return a.Concat(b)
            .GroupBy(map => map.Name)
            .Select(mg => new Map
            {
                Name = mg.Key,
                Properties = mg.SelectMany(v => v.Properties)
                    .GroupBy(p => p.Name)
                    .Select(pg => new MapProperty { Name = pg.Key })
            });
    }

    public static void Main()
    {
        var mapsA = new[]
        {
            new Map
            {
                Name = "MapA",
                Properties = new[]
                {
                    new MapProperty { Name = "Jumps" },
                    new MapProperty { Name = "Hops" },
                }
            },
            new Map
            {
                Name = "MapB",
                Properties = new[]
                {
                    new MapProperty { Name = "Jumps" },
                    new MapProperty { Name = "Skips" },
                }
            }
        };
        var mapsB = new[]
        {
            new Map
            {
                Name = "MapA",
                Properties = new[]
                {
                    new MapProperty { Name = "Jumps" },
                    new MapProperty { Name = "Times" },
                }
            },
            new Map
            {
                Name = "MapC",
                Properties = new[]
                {
                    new MapProperty { Name = "Jumps" },
                    new MapProperty { Name = "Skips" },
                }
            }
        };

        var mapsC = Merge(mapsA, mapsB);

        foreach (var map in mapsC)
        {
            Console.WriteLine($"{map.Name}");
            foreach (var prop in map.Properties)
            {
                Console.WriteLine($"\t{prop.Name}");
            }
        }
    }
}

輸出:

MapA
    Jumps
    Hops
    Times
MapB
    Jumps
    Skips
MapC
    Jumps

Merge是重要的一點。 它首先將ab all放入一個列表中,然后GroupBy名稱形成具有相同名稱的映射組。 Select需要每個組,使新的Map與所有的內容Maps在該組中(這是合並!)。 然后我對新的合並地圖的內容做了同樣的事情,並將MapProperty組合在一起並合並/合並它們。

在您的具體情況下,您需要更多的工作和級別來合並所有內容。 我建議找到一種方法為樹中的每個級別創建一個Merge方法,並從每個父級別調用下一級別,這樣你就不會得到一個龐大的 linq鏈。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM