我有三個串列,其中包含具有以下結構的物件:
List1
- Status
- ValueA
List2
- Status
- ValueB
List3
- Status
- ValueC
我想按狀態連接串列以獲得包含具有以下結構的物件的最終串列:
- Status
- ValueA
- ValueB
- ValueC
并非每個串列都具有所有狀態。所以一個簡單的(左)加入是行不通的。任何想法如何達到預期的結果?我試過了
var result = from first in list1
join second in list2 on first.Status equals second.Status into tmp1
from second in tmp1.DefaultIfEmpty()
join third in list3 on first.Status equals third.Status into tmp2
from third in tmp2.DefaultIfEmpty()
select new { ... };
但結果缺少狀態。這是一個完整的 MRE:
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
List<A> first = new List<A>() { new A("FOO", 1), new A("BAR", 2) };
List<B> second = new List<B>() { new B("FOO", 6), new B("BAR", 3) };
List<C> third = new List<C>() { new C("BAZ", 5) };
var result = from f in first
join s in second on f.Status equals s.Status into tmp1
from s in tmp1.DefaultIfEmpty()
join t in third on f.Status equals t.Status into tmp2
from t in tmp2.DefaultIfEmpty()
select new
{
Status = f.Status,
ValueA = f.ValueA,
ValueB = s.ValueB,
ValueC = t.ValueC,
};
}
}
public record A(string Status, int ValueA);
public record B(string Status, int ValueB);
public record C(string Status, int ValueC);
uj5u.com熱心網友回復:
不幸的是,不清楚應該發生什么,如果一個狀態在一個串列中多次出現,導致您的聚合每個狀態只能包含一個值。
解決此問題的一種可能性是:
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
List<A> first = new List<A>() { new A("FOO", 1), new A("BAR", 2) };
List<B> second = new List<B>() { new B("FOO", 6), new B("BAR", 3) };
List<C> third = new List<C>() { new C("BAZ", 5) };
var allStates = first.Select(a => a.Status)
.Concat(second.Select(b => b.Status))
.Concat(third.Select(c => c.Status))
.Distinct();
var result = allStates
.Select(Status => new
{
Status,
ValueA = first.FirstOrDefault(a => a.Status == Status),
ValueB = second.FirstOrDefault(b => b.Status == Status),
ValueC = third.FirstOrDefault(c => c.Status == Status),
});
foreach (var item in result)
{
Console.WriteLine(item);
}
}
}
public record A(string Status, int ValueA);
public record B(string Status, int ValueB);
public record C(string Status, int ValueC);
根據必須聚合的專案數量以及每個狀態僅出現一次或從不出現的前提,將串列轉換為 , 等以改進查找并在聚合中執行類似的操作可能是有意義Dictionary<string, A>的Dictionary<string, B>:
ValueA = dictFirst.ContainsKey(Status) ? dictFirst[Status] : null
為了進一步改進(此行進行兩次查找),您還可以考慮出這樣的方法
private static T GetValueOrDefault<T>(IReadOnlyDictionary<string, T> dict, string status)
{
dict.TryGetValue(status, out T value);
return value;
}
并在.Select()方法中呼叫它
ValueA = GetValueOrDefault(firstDict, Status);
可以通過以下方式為串列創建字典:
var firstDict = first.ToDictionary(a => a.Status);
uj5u.com熱心網友回復:
假設狀態名稱在每個串列中都是唯一的,這里是在單個查詢中借助switch expressions(自 C# 8.0 起可用)的解決方案:
using System;
using System.Linq;
using System.Collections.Generic;
List<A> first = new List<A>() { new A("FOO", 1), new A("BAR", 2) };
List<B> second = new List<B>() { new B("FOO", 6), new B("BAR", 3) };
List<C> third = new List<C>() { new C("BAZ", 5) };
var result = first
// concat lists together
.Cast<object>()
.Concat(second)
.Concat(third)
// group on Status value with help of switch expression
.GroupBy(el => el switch {
A a => a.Status,
B b => b.Status,
C c => c.Status,
},
// project groups with anonymous type
(Status, group) => new {
Status,
ValueA = group.OfType<A>().Select(a => a.ValueA).Cast<int?>().FirstOrDefault(),
ValueB = group.OfType<B>().Select(b => b.ValueB).Cast<int?>().FirstOrDefault(),
ValueC = group.OfType<C>().Select(c => c.ValueC).Cast<int?>().FirstOrDefault()
});
public record A(string Status, int ValueA);
public record B(string Status, int ValueB);
public record C(string Status, int ValueC);
uj5u.com熱心網友回復:
這不能使用左連接。首先您必須獲取所有鍵,然后使用所有鍵左連接其他串列:
var keys = first.Select(item => item.Status).ToList();
keys.AddRange(second.Select(item => item.Status));
keys.AddRange(third.Select(item => item.Status));
keys = keys.Distinct().ToList();
var result = (from k in keys JOIN
f in first on k equals f.Status into tmp0
from f in tmp0.DefaultIfEmpty()
join s in second on k equals s.Status into tmp1
from s in tmp1.DefaultIfEmpty()
join t in third on k equals t.Status into tmp2
from t in tmp2.DefaultIfEmpty()
select new {
Status = k,
ValueA = f?.ValueA,
ValueB = s?.ValueB,
ValueC = t?.ValueC,
}
).ToList();
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/438267.html
上一篇:c#groupbyorderbythenby嘗試顯式指定型別引數
下一篇:c#-從嵌套串列中查找字串
