Linq OrderBy针对特定值

Jon*_*ker 40 c# linq linq-to-objects

Linq是否有办法在不知道值的顺序的情况下对一组值(本例中为字符串)执行OrderBy?

考虑这些数据:

A
B
A
C
B
C
D
E
Run Code Online (Sandbox Code Playgroud)

而这些变量:

string firstPref,secondPref,thirdPref;

当值设置如下:

firstPref = 'A';
secondPref = 'B';
thirdPref = 'C';
Run Code Online (Sandbox Code Playgroud)

是否可以像这样订购数据:

A
A
B
B
C
C
D
E
Run Code Online (Sandbox Code Playgroud)

Dan*_*ner 102

如果将首选项放入列表中,可能会变得更容易.

List<String> data = new List<String> { "A","B","A","C","B","C","D","E" };
List<String> preferences = new List<String> { "A","B","C" };

IEnumerable<String> orderedData = data.OrderBy(
   item => preferences.IndexOf(item));
Run Code Online (Sandbox Code Playgroud)

这将使所有项目不在preferences前面,因为IndexOf()返回-1.特别的解决方法可能是逆转preferences并命令结果降序.这变得相当丑陋,但有效.

IEnumerable<String> orderedData = data.OrderByDescending(
   item => Enumerable.Reverse(preferences).ToList().IndexOf(item));
Run Code Online (Sandbox Code Playgroud)

如果你连接preferences,解决方案会变得更好一些data.

IEnumerable<String> orderedData = data.OrderBy(
   item => preferences.Concat(data).ToList().IndexOf(item));
Run Code Online (Sandbox Code Playgroud)

我不喜欢Concat()ToList()那里.但就目前而言,我没有什么好办法.我正在寻找一个很好的技巧,将-1第一个例子变成一个大数字.

  • 不,使用Math.Abs​​将"不推荐"值与第二个首选项混合使用.尝试使用一些主要不是为了开始排序的数据. (3认同)
  • 使用第二个列表和indexOf +1很好的移动. (2认同)
  • 您可以在初始化 `new string[] { "A", "B", "C" }.Reverse();` 中反转首选项,因此仅在对象创建时执行一次。如果将其设为静态(在本例中,没有理由不能),那么它将在类加载时完成,并且仅加载一次。请注意,`List&lt;T&gt;` 隐藏了 Linq `Reverse()` 扩展及其返回 void - 这就是我选择在这里使用数组的原因,考虑到它无论如何都不需要是动态的。 (2认同)

小智 19

除了@DanielBrückner在答案和最后定义的问题:

我不喜欢那里的Concat()和ToList().但就目前而言,我并没有真正好的方法.我正在寻找一个很好的技巧,将第一个>示例的-1转换成一个大数字.

我认为解决方案是使用语句lambda而不是表达式lambda.

var data = new List<string> { "corge", "baz", "foo", "bar", "qux", "quux" };
var fixedOrder = new List<string> { "foo", "bar", "baz" };
data.OrderBy(d => {
                    var index = fixedOrder.IndexOf(d);
                    return index == -1 ? int.MaxValue : index; 
                  });
Run Code Online (Sandbox Code Playgroud)

有序数据是:

foo 
bar 
baz 
corge 
qux 
quux 
Run Code Online (Sandbox Code Playgroud)


Guf*_*ffa 5

将首选值放在字典中。与在列表中查找值是O(n)操作相比,在字典中查找键是一项O(1)操作,因此扩展性更好。

为每个首选值创建一个排序字符串,以便将它们放在其他值之前。对于其他值,该值本身将用作排序字符串,以便对它们进行实际排序。(使用任意高值只会将它们放在未排序列表的末尾)。

List<string> data = new List<string> {
    "E", "B", "D", "A", "C", "B", "A", "C"
};
var preferences = new Dictionary<string, string> {
    { "A", " 01" },
    { "B", " 02" },
    { "C", " 03" }
};

string key;
IEnumerable<String> orderedData = data.OrderBy(
    item => preferences.TryGetValue(item, out key) ? key : item
);
Run Code Online (Sandbox Code Playgroud)