我有一門課,例如:
public class SomeClass {
public HashSet<int> Items;
}
我想將 SomeClass 與其他不共享任何專案的 SomeClass 組合在一起。
示例:假設我們有 3 個 SomeClass (S1-S4),例如:
S1:
? 專案:
1、2、6 S2:
? 專案:3、4、5
S3:
? 專案:1
S4:
? 專案:1、5
S5 :
? 專案:8, 9
在這種情況下,組應如下所示:
G1:S1、S2、S5
G2:S3
G3:S4
理想情況下,專案應放置在成員最少的組中,以便所有組的大小相對相同。
如何做到這一點?
uj5u.com熱心網友回復:
沒有辦法在 Linq 中定義這個分組。GroupBy在 Linq 中需要定義“相等”,并且該定義必須是可傳遞的,這意味著 ifA=B和B=C, thenA=C必須為真。您的定義不是傳遞性的,如您的輸入S1=S2, 和S2=S3,但是S1!=S3。
您可以做的是遍歷所有專案,根據需要創建新組,并將專案添加到組中以保持您宣告的較小尺寸。
因此,您可以從 開始S1,查找包含 的其他專案,1并將它們放入新組(S3在S4本例中)。然后查找包含2將它們放入在步驟 1 中創建的組中的專案,交替組。
按照這個邏輯,你應該最終得到:
G1: S1, S2
G2: S3, S5
G3: S4
但是,再一次,這不能在 Linq 中完成 - 您必須自己撰寫回圈和分組邏輯。
uj5u.com熱心網友回復:
答案僅出于娛樂目的,提供了一個陳述句轉換,甚至可以將其視為 LINQ,您將“聚合”視為 LINQ(LINQPad-ready):
void Main()
{
var list = new[] {
new SomeClass("s1", 1,2,6),
new SomeClass("s2", 3,4,5),
new SomeClass("s3", 1),
new SomeClass("s4", 1,5),
new SomeClass ("s5", 8,9)
};
var r = list.Aggregate(new List<IEnumerable<SomeClass>>().AsEnumerable(),
(result, cur) => result
// groups that should be copied
.Where(w => w != result.FirstOrDefault(
x => x.SelectMany(c => c.Items).Intersect(cur.Items).Count() == 0))
.Concat(Enumerable.Repeat(
// adding to existing one
(result.FirstOrDefault(
x => x.SelectMany(c => c.Items).Intersect(cur.Items).Count() == 0) ??
// adding to new one
new List<SomeClass>())
// add current item to existing/new group
.Concat(Enumerable.Repeat(cur, 1)),
1))
);
r.Dump();
}
// Define other methods and classes here
public class SomeClass
{
public SomeClass(string name, params int[] items)
{
Name = name;
Items= new HashSet<int>(items);
}
public string Name;
public HashSet<int> Items;
}
類的解釋:
在每次迭代中
- 將組串列分成兩半 - 第一個合適的組添加當前專案,其余的使用相同的條件。
- 對于其余的組(
.Where選擇除潛在的第一個合適的組之外的所有組),讓他們原封不動地移動到下一個迭代 - 對于合適的組,有兩個選項 - 我們實際上有一個要添加的組,或者沒有這樣的組,我們需要創建一個新組。為了統一我們剛剛使用的代碼
result.FirstOrDefault(...) ?? new List<...>()- 這給出了一個添加新專案的串列,該專案要么具有來自先前迭代的專案,要么具有新的專案。 - 將當前專案添加到合適的組 -
.Concat需要我們用 IEnumerable 構建的Enumerable.Repeat(cur,1)。 - 將“要復制的組串列”與“具有當前元素的單個組串列”連接起來。
如果您嘗試自己破解相同的代碼,請注意:
- it is very easy to add "current" group to multiple existing groups if you just check "no intersection". We must only consider first suitable group to get code working correctly
- subsequently it is easy to lose existing if you try to use some sort of "intersects" filter that doesn't stop on first match.
- Think about top level
Concatas "split list into two parts based on true/false" and merge modified results. - Creating new group is easy to get wrong/miss altogether.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/451555.html
