按特定订单排序列表

时间:2016-03-29 05:27:24

标签: c# .net

我有一个List我有一个新订单List应该包含int[]中的项目我希望List中的项目应该重新按照int[]中的项目排序。这是我的代码:

   class Program
    {
        static void Main(string[] args)
        {
            List<Test> tests = new List<Test>() { 
                new Test(){ No = 201 },
                new Test(){ No = 101 },
                new Test(){ No = 300 },
                new Test(){ No = 401 },
                new Test(){ No = 500 },
                new Test(){ No = 601 }
            };


            int[] newOrder = new int[6] { 201, 401, 300, 101, 601, 500 };

            //after the opration the List should contain items in order 201, 401, 300, 101, 601, 500

            List<Test> newTests = new List<Test>();

            foreach(var order in newOrder)
            {
                var item = tests.SingleOrDefault(t => t.No == order);

                if (item != null)
                    newTests.Add(item);
            }


        }

    }

这很好用。但它会创建一个单独的List并对其执行操作。有没有更好的方法我可以使用内置的.Net操作或者可以在同一个List上执行操作而不创建这些Temp List等?

谢谢。

4 个答案:

答案 0 :(得分:6)

在运行这样的类型时,您需要考虑性能。

如果您只想要少数几个元素,那么Pedro's solution就可以了。

如果您希望有许多元素(例如,100或者1000),那么为每个元素搜索整个tests集合并不是一个好主意在newOrder。在这种情况下,对所有索引/排序顺序查找使用Dictionary会很有帮助。尝试这样的事情:

List<Test> tests = new List<Test>() { 
    new Test(){ No = 101 },
    new Test(){ No = 201 },
    new Test(){ No = 300 },
    new Test(){ No = 401 },
    new Test(){ No = 500 },
    new Test(){ No = 601 }
};


int[] newOrder = new int[6] { 201, 401, 300, 101, 601, 500 };

// Create a Dictionary/hashtable so we don't have to search in newOrder repeatedly
// It will look like this: { {201,0}, {401,1}, {300,2}, {101,3}, {601,4}, {500,5} }
Dictionary<int, int> newOrderIndexedMap = Enumerable.Range(0, newOrder.Length - 1).ToDictionary(r => newOrder[r], r => r);

// Order using 1 CPU
var orderedTests = tests.OrderBy(test => newOrderIndexedMap[test.No]);
// Order using multi-threading
var orderedInParallelTests = tests.AsParallel().OrderBy(test => newOrderIndexedMap[test.No]);

// Order using 1 CPU, when it's possible that a match will not be found in newOrder
var orderedTestsSafe = tests.OrderBy(test => 
    {
        int index;
        bool foundIndex = newOrderIndexedMap.TryGetValue(test.No, out index);
        return foundIndex ? index : Int32.MaxValue;
    });

请注意,此答案和佩德罗都认为newOrder包含tests元素中包含的所有值,反之亦然。

答案 1 :(得分:2)

var newTesties= newOrder.Select(o => tests.First(t => t.No == o));

基本上,我选择每个号码&#39; o&#39;在newOrder中,并使用它来获取相应的测试。你最终会得到一个新的清单。

答案 2 :(得分:2)

使用左连接可以是使用自定义排序的方法之一。对于任何与自定义排序不匹配的项目,请使用从末尾开始的列表的原始顺序

var results = from a in tests.Select((r, i) => new {item = r, Index = i})
              // left join
              from b in newOrder.Select((r, i) => new { item = r, Index = i })
                                .Where(b => a.item.No == b.item).DefaultIfEmpty() 
              // Not in order list then use original ordering
              orderby (b == null ? tests.Count() + a.Index : b.Index) 
              select a.item;

.Net Fiddle

答案 3 :(得分:1)

尝试加入你的数组并像这样列出

newOrder.Join(tests, no => no, tst => tst.No, (no, tst) => tst)