![](/img/trans.png)
[英]How to OrderBy on a generic IEnumerable (IEnumerable<T>) using LINQ in C#?
[英]C# LINQ OrderBy values from another List(IEnumerable)
假設我們有一個字符串列表var listA = new List<string> {"B", "C", "A"}
,並且它以所需的方式排序。 並且,有一個 object 定義如下:
public class Sample {
public string Letter {get;set;} // "A","B","C","D","#"
public string Number {get;set;} // not relevant
}
此外,還有另一個列表List<Sample> listB
,我想對它進行排序,首先是字母值為“B”的對象,然后是“C”,最后是“A”,所以尊重相同按照 listA 中的順序排列。 有任何想法嗎? :)
編輯:字母屬性可以有更廣泛的字符,不像 listA 只能有那些 3. 預期順序“B”,“C”,“A”......“所有 rest,順序不相關”
假設Letter
的值在listA
內。 如果假設不成立,則值得考慮重新設計算法。 並且它可能取決於超出范圍的預期訂單的要求。
var sortedSamples = listB.OrderBy(x=>listA.IndexOf(x.Letter));
為了獲得更好的性能,將訂單緩存到字典中:
var orders = new Dictionary<string, int>();
for (int i = 0; i < listA.Count; i++)
{
orders.Add(listA[i], i);
}
var sortedSamples = listB.OrderBy(x=>orders[x.Letter]);
如果Letter
的可能值范圍比listA
,那么最好像這樣構造orders
:
foreach (string letter in listB.Select(x=>x.Letter))
{
orders.Add(letter, listA.IndexOf(letter));
}
更新
如果letters
的范圍超出listA
,並且由於 OP 希望 out 的位於末尾:
var orders = new Dictionary<string, int>();
for (int i = 0; i < listA.Count; i++)
{
orders.Add(listA[i], i);
}
int lastIndex = listA.Count;
foreach (string letter in listB.Select(x=>x.Letter)
.Distinct().Except(listA))
{
orders.Add(letter, lastIndex);
}
這是@nannanas answer的方法體的具體實現,當listA
不包含listB
中存在的所有字母時,它也有效:
listB = listA.Union(listB.Select(entry => entry.Letter))
.Join(listB,
letter => letter,
sample => sample.Letter,
( _, sample ) => sample)
.ToList();
示例小提琴在這里。
假設我們有以下列表:
var listA = new List<string> { "B", "C", "A" };
var listB = new List<Sample>
{
new Sample { Letter = "E", Number = "1" },
new Sample { Letter = "C", Number = "2" },
new Sample { Letter = "A", Number = "3" },
new Sample { Letter = "B", Number = "4" },
new Sample { Letter = "D", Number = "5" }
};
listB.Select(entry => entry.Letter)
將提取listB
中的每個Letter
值,導致:
{ "E", "C", "A", "B", "D" }
listA.Union(listB.Select(entry => entry.Letter))
使用.Union()創建listA
和listB
的Letter
值的集合並集,方法是首先生成listA
集合中的每個不同項目( "B", "C", "A"
), 然后從listB
中產生Letter
集合中的每個不同的項目,這些項目不存在於listA
( "E", "D"
) 中; 導致:
{“B”,“C”,“A”,“E”,“D”}
我們現在有了希望listB
反映的字母順序:首先是listA
給出的順序,然后是listB
中出現的剩余字母。
.Join()根據每個序列的鍵選擇器定義的關聯鍵將外部序列與內部序列相關聯; 然后根據結果選擇器從關聯中返回一個IEnumerable<T>
:
outerSequence.Join(innerSequence,
outerItem => /* */, // key selector (outerItem is a string)
innerItem => /* */, // key selector (innerItem is a Sample)
( associatedOuterItem, associatedInnerItem ) => /* */) // result selector
{ "B", "C", "A", "E", "D" }
因此是.Join()
操作中的外部序列。 .Join()
操作的內部序列是listB
。 通過使用.Join()
,我們可以通過序列的匹配鍵選擇器將外部序列中的項目與內部序列中的項目相關聯。
對於外部序列,我們將鍵選擇器定義為整個項目:
letter => letter // alternatively: outerItem => outerItem
例如,外部序列中的前兩個項目是"B"
和"C"
; 因此,外部序列中前兩項的關聯鍵是"B"
和"C"
。
對於內部序列,我們將鍵選擇器定義為Sample
object 的Letter
屬性:
sample => sample.Letter // alternatively: innerItem => innerItem.Letter
例如,內部序列中的前兩個項目是Sample { Letter = "E", Number = "1" }
和Sample { Letter = "C", Number = "2" }
; 因此,內部序列中前兩個項目的關聯鍵是每個項目的Letter
值: "E"
和"C"
。
因此,外部和內部序列的全套密鑰選擇器分別是:
{“B”,“C”,“A”,“E”,“D”}
{ "E", "C", "A", "B", "D" }
.Join()
操作現在根據鍵選擇器關聯每個序列中的項目。 關聯保持外部序列提供的順序,並且可以說明如下:
來自外部序列的項目 | 來自內部序列的項目 |
---|---|
"B" |
Sample { Letter = "B", Number = "4" } |
"C" |
Sample { Letter = "C", Number = "2" } |
"A" |
Sample { Letter = "A", Number = "3" } |
"E" |
Sample { Letter = "E", Number = "1" } |
"D" |
Sample { Letter = "D", Number = "5" } |
最后一個.Join()
輸入參數是結果選擇器,它定義了每個關聯應返回的內容。 鑒於我們只需要內部序列中的項目,我們在結果選擇器中指定:
( _, sample ) => sample
(結果選擇器可以重寫為例如( letter, sample ) => sample
,但是由於外部序列(稱為letter
)中的項目不感興趣,我只是簡單地丟棄了 ( _
) 我的 object例子。)
你應該使用這樣的東西
var listA = new List<string> { "B", "C", "A" };
var listB = new List<string> { "A", "B", "C" };
listB = listB.OrderBy(d => listA.IndexOf(d)).ToList();
// listB: "B", "C", "A"
您可以使用此擴展,它還支持通過特定屬性(例如 id 而不是引用)比較列表中的條目
public static IEnumerable<TFirst> OrderBy<TFirst, TSecond, TKey>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TKey> firstKeySelector, Func<TSecond, TKey> secondKeySelector) =>
second
.Join(
first,
secondKeySelector,
firstKeySelector,
(_, firstItem) => firstItem);
這將在second
項目中對項目進行排序,就像在first
使用兩個鍵選擇器比較它們時已經對它們進行排序一樣。
請注意,這僅在first
中的所有鍵也存在於second
中時才有效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.