如何根据订购排序
可以说我有物品
items : [{id:1,...}, {id:2,...}, {id:3,...}]
并命令:[ 2,3,1 ]得到一个可枚举的
items : [{id:2,...}, {id:3,...}, {id:1,...}]
我希望它能成为符合标准的东西
items.Select(o => new {key = ordering[i++], value = o}) .OrderBy(k => k.key) .Select(o => o.value)
但有更清洁的解决方案吗?
我已经validation了这项工作(HimBromBeere,Domysee,qxg)
var expectedOrder = ordering.Select(x => result.First(o => o.Id == x)); var expectedOrder = result.OrderBy(item => Array.FindIndex(ordering,i => i == item.Id)); var expectedOrder = result.OrderBy(item => ordering.ToList().FindIndex(i => i == item.Id)); var expectedOrder = from o in ordering join i in result on o equals i.Id select i;
Fwi,这是用于validation测试:
[Test] [TestCase(1, 2, 3)] [TestCase(1, 3, 2)] [TestCase(2, 1, 3)] [TestCase(2, 3, 1)] [TestCase(3, 1, 2)] public void Test_Should_Fail_If_GetMessages_Does_Not_Return_Sorted_By_Sent_Then_By_Id_Result(params int[] ordering) { var questions = GetQuestionsData(); Mock.Get(_questionService) .Setup(o => o.GetQuestions()) .Returns(questions); var result = _mailboxService.GetMessages(); var expectedOrder = ordering.Select(x => result.First(o => o.Id == x)); // Act Action sortOrder = () => expectedOrder.Should() .BeInDescendingOrder(o => o.Sent) .And.BeInDescendingOrder(o => o.Id); // Assert sortOrder.ShouldThrow(); }
我猜是这样的:
var result = ordering.Select(x => items.First(y => y.id == x.id));
工作范例:
var items = new[] { new { id = 1, name = "1" }, new { id = 2, name = "2" }, new { id = 3, name = "3" }, new { id = 4, name = "4" } }; var result = new[] { 2, 3, 1 }.Select(x => items.First(y => y.id == x));
这也会过滤掉那些items
,其索引不包含在ordering
。
如果您的ID是连续的,您可以重新排列订单数组以包含每个索引 – 结果数组中具有相同索引的ID的位置。 这可以这样做:
int[] order = new[] {2, 3, 1}; order = Enumerable.Range(1, order.Length) .OrderBy(x => order[x - 1]) .ToArray(); //Now order = { 3, 1, 2 } which are the one-based indices of each position in the original order array.
现在您可以使用该结果数组来订购Enumerable
:
items = items.OrderBy(x => order[x.Id - 1]);
请注意,如果您首先以这种方式表示您的订单数组,那么第一个Linq
将是不必要的,这样您就没有多余的迭代或子Linq
:
int[] order = new[] {3, 1, 2}; //1 is third, 2 is first, 3 is second. items = items.OrderBy(x => order[x.Id - 1]);
您可以使用Select
的重载来代替索引
items.Select((o,i) => new {key = ordering[i+1], value = o}) .OrderBy(k => k.key) .Select(o => o.value);
这将更好,因为它消除了示例中捕获的i
变量。
如果ordering
是List
,您可以这样做:
items.OrderBy(item => ordering.FindIndex(i => i == item.id))
唯一的改进是它不需要再次订购或新对象,但基本上与原始代码相同。
var query = from o in ordering join i in items on o equals i.Id select i;