[英]C# LINQ OrderBy values from another List(IEnumerable)
Let's imagine we have a list of strings var listA = new List<string> {"B", "C", "A"}
, and it is sorted in the desired manner.假设我们有一个字符串列表var listA = new List<string> {"B", "C", "A"}
,并且它以所需的方式排序。 And, there is an object defined like:并且,有一个 object 定义如下:
public class Sample {
public string Letter {get;set;} // "A","B","C","D","#"
public string Number {get;set;} // not relevant
}
Also, there is another list, List<Sample> listB
, and I want to sort it in a way that first comes objects with Letter values "B", then "C" and on the end, "A", so to respect same order as it is in the listA.此外,还有另一个列表List<Sample> listB
,我想对它进行排序,首先是字母值为“B”的对象,然后是“C”,最后是“A”,所以尊重相同按照 listA 中的顺序排列。 Any ideas?有任何想法吗? :) :)
EDIT: Letter property can have a wider range of characters, unlike listA which can have just those 3. Expected order "B","C", "A"..."all the rest, order not relevant"编辑:字母属性可以有更广泛的字符,不像 listA 只能有那些 3. 预期顺序“B”,“C”,“A”......“所有 rest,顺序不相关”
Assume value of Letter
are within listA
.假设Letter
的值在listA
内。 It's worth considering redesigning the algorithm if the assumption is false.如果假设不成立,则值得考虑重新设计算法。 And it may depend on requirement of expected order the out of range ones.并且它可能取决于超出范围的预期订单的要求。
var sortedSamples = listB.OrderBy(x=>listA.IndexOf(x.Letter));
For better performance, cache the orders into a dictionary:为了获得更好的性能,将订单缓存到字典中:
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]);
If possible values range of Letter
is much smaller than listA
, then better consturct orders
like this:如果Letter
的可能值范围比listA
,那么最好像这样构造orders
:
foreach (string letter in listB.Select(x=>x.Letter))
{
orders.Add(letter, listA.IndexOf(letter));
}
Update更新
If letters
' range are out of listA
, and since OP want the out ones to be at the end:如果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);
}
Here is a specific implementation of the method body of @nannanas's answer , which also works when listA
does not contain all letters present in listB
:这是@nannanas answer的方法体的具体实现,当listA
不包含listB
中存在的所有字母时,它也有效:
listB = listA.Union(listB.Select(entry => entry.Letter))
.Join(listB,
letter => letter,
sample => sample.Letter,
( _, sample ) => sample)
.ToList();
Example fiddle here .示例小提琴在这里。
Let's say we have the following lists:假设我们有以下列表:
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)
will extract each Letter
value in listB
, resulting in: listB.Select(entry => entry.Letter)
将提取listB
中的每个Letter
值,导致:
{ "E", "C", "A", "B", "D" } { "E", "C", "A", "B", "D" }
listA.Union(listB.Select(entry => entry.Letter))
uses .Union() to create the set union of listA
and listB
's Letter
values by first yielding each distinct item in the set of listA
( "B", "C", "A"
), then yielding each distinct item in the set of Letter
s from listB
that are not present in listA
( "E", "D"
); listA.Union(listB.Select(entry => entry.Letter))
使用.Union()创建listA
和listB
的Letter
值的集合并集,方法是首先生成listA
集合中的每个不同项目( "B", "C", "A"
), 然后从listB
中产生Letter
集合中的每个不同的项目,这些项目不存在于listA
( "E", "D"
) 中; resulting in:导致:
{ "B", "C", "A", "E", "D" } {“B”,“C”,“A”,“E”,“D”}
We now have the order of the letters that we want listB
to reflect: First, the order given by listA
, then, the remaning letters present in listB
.我们现在有了希望listB
反映的字母顺序:首先是listA
给出的顺序,然后是listB
中出现的剩余字母。
.Join() associates an outer sequence with an inner sequence based on association keys defined by a key selector for each sequence ; .Join()根据每个序列的键选择器定义的关联键将外部序列与内部序列相关联; and then returns an IEnumerable<T>
from the associations based on the result selector :然后根据结果选择器从关联中返回一个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" }
is thereby the outer sequence in the .Join()
operation. { "B", "C", "A", "E", "D" }
因此是.Join()
操作中的外部序列。 The inner sequence of the .Join()
operation is listB
. .Join()
操作的内部序列是listB
。 By using .Join()
, we can associate items in the outer sequence with items in the inner sequence by the sequences' matching key selectors .通过使用.Join()
,我们可以通过序列的匹配键选择器将外部序列中的项目与内部序列中的项目相关联。
For the outer sequence , we define the key selector as being the whole item:对于外部序列,我们将键选择器定义为整个项目:
letter => letter // alternatively: outerItem => outerItem
As an example, the two first items in the outer sequence are "B"
and "C"
;例如,外部序列中的前两个项目是"B"
和"C"
; so, the association key for the first two items in the outer sequence are "B"
and "C"
.因此,外部序列中前两项的关联键是"B"
和"C"
。
For the inner sequence , we define the key selector as being the Letter
property of the Sample
object:对于内部序列,我们将键选择器定义为Sample
object 的Letter
属性:
sample => sample.Letter // alternatively: innerItem => innerItem.Letter
As an example, the two first items in the inner sequence are Sample { Letter = "E", Number = "1" }
and Sample { Letter = "C", Number = "2" }
;例如,内部序列中的前两个项目是Sample { Letter = "E", Number = "1" }
和Sample { Letter = "C", Number = "2" }
; so, the association key for the first two items in the inner sequence are each item's Letter
value: "E"
and "C"
.因此,内部序列中前两个项目的关联键是每个项目的Letter
值: "E"
和"C"
。
Hence, the full set of key selectors for the outer and inner sequences are, respectively:因此,外部和内部序列的全套密钥选择器分别是:
{ "B", "C", "A", "E", "D" } {“B”,“C”,“A”,“E”,“D”}
{ "E", "C", "A", "B", "D" } { "E", "C", "A", "B", "D" }
The .Join()
operation now associates the items in each sequence based on the key selectors . .Join()
操作现在根据键选择器关联每个序列中的项目。 The associations keep the order provided by the outer sequence , and can be illustrated as follows:关联保持外部序列提供的顺序,并且可以说明如下:
Item from outer sequence来自外部序列的项目 | Item from inner sequence来自内部序列的项目 |
---|---|
"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" } |
The last .Join()
input parameter is the result selector , which defines what should be returned from each association.最后一个.Join()
输入参数是结果选择器,它定义了每个关联应返回的内容。 Seeing as we only need the item from the inner sequence , we specify that in the result selector :鉴于我们只需要内部序列中的项目,我们在结果选择器中指定:
( _, sample ) => sample
(The result selector could have been rewritten to eg ( letter, sample ) => sample
, but seeing as the items from the outer sequence (referred to as letter
) are not of interest, I have simply discarded ( _
) that object in my example.) (结果选择器可以重写为例如( letter, sample ) => sample
,但是由于外部序列(称为letter
)中的项目不感兴趣,我只是简单地丢弃了 ( _
) 我的 object例子。)
You should using something like this你应该使用这样的东西
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"
You could use this extension which also supports comparing the entries in the lists by a specific property (eg id instead of reference)您可以使用此扩展,它还支持通过特定属性(例如 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);
this will sort the items in second
the same way as they are already sorted in first
comparing them using both key selectors.这将在second
项目中对项目进行排序,就像在first
使用两个键选择器比较它们时已经对它们进行排序一样。
Be aware that this only works if ALL the keys in first
are also present in second
.请注意,这仅在first
中的所有键也存在于second
中时才有效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.