[英]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.