将列表排序为另一个列表

时间:2011-08-01 08:51:22

标签: linq list generics sorting collections

我有两个列表包含相同的ID而不是相同的顺序 是否有一种方法将列表2排序为列表2的相同顺序

List 1:
Views IDs: 341932,346447,354534,335743,351166,350016,352398,354390,351389,342070,335667,338576,335761,354504,352421,350090,342114,351396,354436,355624,352339,352378,355580

List 2: 
FromLol Ids: 335667,335743,335761,338576,341932,342070,342114,346447,350016,350090,351166,351389,351396,352339,352378,352398,352421,354390,354436,354504,354534,355580,355624

我使用简单的循环,但我正在寻找更好的性能

for (int i = 0; i < List1.Count; i++)
{
    for (int j = 0; j < List2.Count; j++) 
    {
        if (List1[i].MediaItemIdId == List2[j].MediaItemID) 
        {
            TempList.Add(List2[j]);
            break;
        }
    }
}

4 个答案:

答案 0 :(得分:2)

好吧,据我所知(从评论到你的问题):你有一个id列表和一个包含这些id的对象列表,现在你想要根据第一个id列表对第二个列表进行排序: / p>

var objectDictionary = List2.ToDictionary(y => y.MediaItemID, y => y);
var newList = new List<YourType>();
List1.ForEach(y => newList.Add(objectDictionary[y.MediaItemID]));

这应该有效,但如果它是更好的表现,我不知道。

更新:代码中第3行的错误,应该是List1而不是List2,代码已更新。

答案 1 :(得分:2)

使用第一个列表作为键选择器的一部分。

 list2.OrderBy(a=>list1.IndexOf(a.Id))

如果密钥是唯一的,并且您不需要按原样保留list1,则可以通过从list1中删除使用的ID来提高性能。

public static IList<T> OrderBy<T, K>(this IList<T> self, Func<T, K> keySelector, IList<K> sortedlist){
            var indices = GetIndices(self, keySelector, sortedlist).Reverse().GetEnumerator();
            indices.MoveNext();
            var result = new List<T>();
            for(int i = self.Count-1;i>=0;i--){
                result.Insert(indices.Current,self[i]);
                indices.MoveNext();
            }
            return result;
        }

        private static IEnumerable<int> GetIndices<T,K>(IEnumerable<T> self, Func<T, K> keySelector, IList<K> sortedlist)
        {
            foreach (var elem in self)
            {
                var key = keySelector(elem);
                yield return sortedlist.IndexOf(key);
            }
        }

答案 2 :(得分:0)

您需要动态创建订单。换句话说,你实际上正在排序:

List1:(Id,PositionInList)。例如[341932,1],[346447,2],... List2:(Id,PositionInList)。例如[335667,1],[335743,2],...

首先创建上述类型(Sql / temp表/行计数或C#/ LINQ / Projection)

然后加入2个Ids ......并找到所需的位置。

然后您可以按位置对结果进行排序。

希望这是有道理的。


更新......好吧有点混乱。问题也是如此; - )

认为你说你有定义订单的清单1。并且您希望将第二个列表排序为相同的顺序。

如果是这样,我会说这样做(它是类似Sql的伪代码)。

您的原始列表:

List1 = 341932, 
             346447, 
             354534,    ...

然后将其选择为list / hash / table,这应该包含原始值和行索引(position)。根据您的语言,有多种方法可以做到这一点。

List1WithIndex = 341932, 1
                 346447, 2
                 354534, 3   ...

现在以相同的顺序获取您想要的第二个列表:

List2 = 335667,335743,335761,338576, ...

现在你需要做的就是将List2值连接/映射到List1WithIndex值。通过Line1WithIndex poisiton排序,一切都应该是正确的顺序...只要你离开加入

如果这不起作用或仍然是胡言乱语,那么可能是一个更完整的例子,说明语言/技术可能会有所帮助......

答案 3 :(得分:0)

性能明智Miroo你的for循环每次LinQ或你想要呈现的方式都会赢得胜利。

正如Occam的Razor校长所说:“最简单的答案通常是正确的答案”。不是每一次,但在这种情况下,我认为是适用的。

例如,我使用秒表创建了下面的简单应用程序,以测量每种排序所需的时间。我添加了你的for循环方法和我已经完成的一种行排序方法。

我运行了一些测试,你的循环比我的一行代码要紧。你所做的任何事情都会为时钟增加更多的周期,你可以通过无数种方式对数组进行排序,甚至可以进一步减少我的数量,但最后你的循环会更快。

如果你的问题不是关于表现,而是关于优雅,减少行数甚至更强大,那么我的答案就会不同。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> list1 = new List<int> { 341932,346447,354534,335743,351166,350016,352398,354390,351389,342070,335667,338576,335761,354504,352421,350090,342114,351396,354436,355624,352339,352378,355580};

            List<int> list2 = new List<int> { 335667,335743,335761,338576,341932,342070,342114,346447,350016,350090,351166,351389,351396,352339,352378,352398,352421,354390,354436,354504,354534,355580,355624};

            List<int> list3 = new List<int>();

            Stopwatch watch = new Stopwatch();

            watch.Start();

            for (int i = 0; i < list1.Count; i++)
            {
                for (int j = 0; j < list2.Count; j++) 
                {
                    if (list1[i] == list2[j]) 
                    {
                        list3.Add(list2[j]);
                        break;
                    }
                }
            }

            watch.Stop();

            Console.WriteLine("Time {0}", watch.ElapsedMilliseconds);

            list3.Clear();

            watch.Reset();

            watch.Start();

            list2.Intersect(list1).OrderBy(o => list1.IndexOf(o)).All(a => { list3.Add(a); return true; });

            watch.Stop();

            Console.WriteLine("Time {0}", watch.ElapsedMilliseconds);
        }
    }
}