簡體   English   中英

嵌套 If 到 LINQ 和 Lambda

[英]Nested If to LINQ and Lambda

凈 6.0

我們公司使用公制布局,記錄看起來像這樣

AAA|0000A|000AA|0001A
AAA|0000A|000AA|0002A
AAA|0000A|000AB|0001B
AAA|0000A|000AB|0002B
AAA|0000B|000BA|0001A
AAA|0000B|000BB|0001B

並將其轉化為這個

AAA|BLANK|BLANK|BLANK

AAA|0000A|BLANK|BLANK
AAA|0000B|BLANK|BLANK

AAA|0000A|000AA|BLANK
AAA|0000A|000AB|BLANK
AAA|0000B|000BA|BLANK
AAA|0000B|000BB|BLANK

AAA|0000A|000AA|0001A
AAA|0000A|000AA|0002A
AAA|0000A|000AA|0003A
AAA|0000A|000AA|0004A
AAA|0000A|000AB|0001B
AAA|0000A|000AB|0002B
AAA|0000B|000BA|0001A
AAA|0000B|000BB|0001B

我有一個自定義 object

public class HierarchyStructure
{
    public string Employer { get; set; }
    public string Level1 { get; set; }
    public string Level2 { get; set; }
    public string Level3 { get; set; }
    public string Level4 { get; set; }
    public bool isRxlvl3 { get; set; }
    public bool isExpired { get; set; }
    public string lvl4SubType { get; set; }

    public HierarchyStructure(string employer,
                              string? level1 = null,
                              string? level2 = null,
                              string? level3 = null,
                              string? level4 = null,
                              bool isRxlvl3 = false,
                              bool isExpired = false,
                              string? lvl4SubType = null)
    {
        this.Employer = employer;
        this.Level1 = string.IsNullOrEmpty(level1) ? string.Empty : level1;
        this.Level2 = string.IsNullOrEmpty(level2) ? string.Empty : level2;
        this.Level3 = string.IsNullOrEmpty(level3) ? string.Empty : level3;
        this.Level4 = string.IsNullOrEmpty(level4) ? string.Empty : level4;
        this.isRxlvl3 = isRxlvl3;
        this.isExpired = isExpired;
        this.lvl4SubType = string.IsNullOrEmpty(lvl4SubType) ? string.Empty : lvl4SubType;
    }

}

我正在嘗試從 static 級別填充到格式化的 output 列表中

    private List<HierarchyStructure> AllLevels => _allLevels;
    private List<HierarchyStructure> LocationLevels => _LocationLevels;

我為每個級別調用開發了方法,但我無法弄清楚如何將它們合並到一個方法中,該方法要么遞歸調用自身,要么動態選擇正確的值。 由於比較和返回值不同,我認為不可能將它們組合起來。

    public bool GetDistinctEmployers()
    {

        var selectedLevels = (from levels in AllLevels
                              select new HierarchyStructure(levels.Employer));

        foreach(HierarchyStructure level in selectedLevels) LocationLevels.Add(level);

        return true;
    }

    public bool GetDistinctLevel1(string emp)
    {

        var selectedLevels = (from levels in AllLevels
                              where levels.Employer == emp
                              select new HierarchyStructure(levels.Employer,levels.Level1));

        foreach(HierarchyStructure level in selectedLevels) LocationLevels.Add(level);

        return true;

    }

    public bool GetDistinctLevel2(string lvl)
    {

        var selectedLevels = (from levels in AllLevels
                              where levels.Level1 == lvl
                              select new HierarchyStructure(levels.Employer,levels.Level1, levels.Level2));

        foreach(HierarchyStructure level in selectedLevels) LocationLevels.Add(level);

        return true;

    }

    public bool GetDistinctLevel3(string lvl)
    {

        var selectedLevels = (from levels in AllLevels
                              where levels.Level2 == lvl
                              select new HierarchyStructure(levels.Employer,levels.Level1, levels.Level2, levels.Level3));

        foreach(HierarchyStructure level in selectedLevels) LocationLevels.Add(level);

        return true;

    }

    public bool GetDistinctLevel4(string lvl)
    {

        var selectedLevels = (from levels in AllLevels
                              where levels.Level3 == lvl
                              select new HierarchyStructure(levels.Employer,levels.Level1, levels.Level2, levels.Level3, levels.Level4));

        foreach(HierarchyStructure level in selectedLevels) LocationLevels.Add(level);

        return true;

    }

當我嘗試將所有這些組合在一起時,它最終變得太嵌套了,我覺得必須有更好的方法來實現這一點。 我相當確定這種級別的嵌套會使我的管道上的質量門出錯。

    public void ProcessLevels()
    {
        if(GetDistinctEmployers())
        {
            foreach(string employer in AllLevels.Select(x => x.Employer))
            {
                if(GetDistinctLevel1(employer))
                {
                    foreach(string level1 in AllLevels.Select(x => x.Level1))
                    {
                        if(GetDistinctLevel2(level1))
                        {
                            foreach(string level2 in AllLevels.Select(x => x.Level2))
                            {
                                if(GetDistinctLevel3(level2))
                                {
                                    foreach(string level3 in AllLevels.Select(x => x.Level3))
                                    {
                                        if(GetDistinctLevel4(level3))
                                        {
                                            SaveData();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

        }
    }

我還得到另一個內聯質量標志,表明可以使用 LINQ 縮短我在此塊中的表達式。我不明白如何簡化我的一行。

...AllLevels.Select(x => x.Employer)
...AllLevels.Select(x => x.Level1)
... etc

我試圖獲取的數據 output 的視圖。

所需數據輸出的視圖

也許您需要首先將每個源行擴展到所有可能級別的東西,然后通過 a.Distinct() 和 an.OrderBy() 運行這些結果。

鑒於:

AAA|0000A|000AA|0001A
AAA|0000A|000AA|0002A
AAA|0000A|000AB|0001B
AAA|0000A|000AB|0002B
AAA|0000B|000BA|0001A
AAA|0000B|000BB|0001B

擴展數據將是:

AAA
AAA|0000A
AAA|0000A|000AA
AAA|0000A|000AA|0001A
AAA
AAA|0000A
AAA|0000A|000AA
AAA|0000A|000AA|0002A
...
AAA
AAA|0000B
AAA|0000B|000BB
AAA|0000B|000BB|0001B

然后 a.Distinct() 和.OrderBy()

AAA
AAA|0000A
AAA|0000A|000AA
AAA|0000A|000AA|0001A
AAA|0000A|000AA|0002A
...
AAA|0000B
AAA|0000B|000BB
AAA|0000B|000BB|0001B
...

您需要一個生成 function 來將每個源行擴展到一個枚舉列表中,而不是可以將其饋送到 a.SelectMany() 中,並且可能還需要定義自定義比較器以供 the.Distinct() 和 a.OrderBy() 函數使用.

就像是:

private static IEnumerable<HierarchyStructure> HierarchyGenerator(this HierarchyStructure level)
{
    yield return new HierarchyStructure(levels.Employer);
    yield return new HierarchyStructure(levels.Employer,levels.Level1);
    yield return new HierarchyStructure(levels.Employer,levels.Level1, levels.Level2);
    yield return new HierarchyStructure(levels.Employer,levels.Level1, levels.Level2, levels.Level3);
    yield return new HierarchyStructure(levels.Employer,levels.Level1, levels.Level2, levels.Level3, levels.Level4);
}
...
LocationLevels = AllLevels
    .SelectMany(levels => levels.HierarchyGenerator())
    .Distinct(...custom HierarchyStructure IEqualityComparer...)
    .OrderBy(hier => hier, ...custom HierarchyStructure IComparer...)
    .ToList();

還有其他方法,例如在每個級別生成不同的值,將它們聯合在一起,然后將它們提供給排序。

就像是:

var level0 = AllLevels
    .Select(levels => newHierarchyStructure(levels.Employer))
    .Distinct(IEqualityComparer...);
...
var level4 = AllLevels
    .Select(levels => new HierarchyStructure(levels.Employer,levels.Level1, levels.Level2, levels.Level3, levels.Level4))
    .Distinct(IEqualityComparer...);

LocationLevels = level0
    .Union(level1)
    .Union(level2)
    .Union(level3)
    .Union(level4)
    .OrderBy(hier => hier, ...custom HierarchyStructure IComparer...)
    .ToList();

在選擇應用不同操作的位置時可能會有一些性能折衷。 使用中間匿名對象也可能有所幫助,例如:

var level1 = AllLevels
    .Select(levels => new {levels.Employer, levels.Level1})
    .Distinct()
    .Select(levels => new HierarchyStructure(levels.Employer,levels.Level1));

這里.Distinct()使用匿名 object 的默認比較器,它比較每個包含的值。

自定義比較器也可以通過實現IComparable接口並入HierarchyStructure class。 HierarchyGenerator() function 也可以成為HierarchyStructure class 中的成員 function。

(對於任何語法錯誤,我提前表示歉意。這是未經測試的。如果有任何評論,我會更新上面的內容。)

這似乎可以很容易地用 LINQ 解決。

我將從這個input開始:

string[] input = new[]
{
    "AAA|0000A|000AA|0001A",
    "AAA|0000A|000AA|0002A",
    "AAA|0000A|000AB|0001B",
    "AAA|0000A|000AB|0002B",
    "AAA|0000B|000BA|0001A",
    "AAA|0000B|000BB|0001B",
};

現在我可以像這樣將其轉換為output

string[][] parts = input.Select(x => x.Split('|')).ToArray();

int max = parts.Max(p => p.Length);

string[][] expanded =
    Enumerable
        .Range(0, max)
        .SelectMany(i => parts.Select(p => p.Take(i + 1).ToArray()).ToArray())
        .DistinctBy(xs => String.Join("|", xs))
        .OrderBy(xs => String.Join("|", xs))
        .ToArray();

string[] output =
    expanded
        .Select(e => String.Join("|", e))
        .ToArray();

這給了我:

AAA
AAA|0000A
AAA|0000A|000AA
AAA|0000A|000AA|0001A
AAA|0000A|000AA|0002A
AAA|0000A|000AB
AAA|0000A|000AB|0001B
AAA|0000A|000AB|0002B
AAA|0000B
AAA|0000B|000BA
AAA|0000B|000BA|0001A
AAA|0000B|000BB
AAA|0000B|000BB|0001B

如果您只想停下來填充網格,只需使用expanded

使用這種方法,源數據的深度是多少並不重要。

暫無
暫無

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

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