首页 > 解决方案 > 在另一个列表中创建按顺序排序的排序列表

问题描述

我有一个已按优先级排序的项目列表,以及一组未排序的项目。每个未排序的项目可能会或可能不会出现在优先列表中。

如何创建一个新列表,其中仅包含优先列表中出现的未排序项目,按照它们出现在优先列表中的顺序?

例如

List<Foo> priorityList = GetPriorityList();
IEnumerable<Foo> unsorteditems = GetSomeItems();

List<Foo> prioritisedItems = new List<Foo>();

foreach (var item in unsorteditems)
{
  if (priorityList.Contains(item))
  {
    //Add item to prioritisedItems in the order it appears in priorityList
  }
}

粗略的实现很容易,但看起来很混乱且效率低下:

List<Foo> sortedList = new List<Foo>();

  foreach (var item in unsortedItems)
  {
    if (priorityList.Contains(item) && !sortedList.Contains(item))
    {
      if (sortedList.Count() < 1)
      {
        sortedList.Add(item);
      }
      else
      {
        foreach (var sortedItem in sortedList)
        {
          if (priorityList.IndexOf(sortedItem) < priorityList.IndexOf(item))
          {
            sortedList.Insert(sortedList.IndexOf(sortedItem), item);
            break;
          }
        }
      }
    }
  }

有没有更清洁的方法来做到这一点?

关于这个主题的其他问题似乎 a) 使用要排序的项目的属性,或 b) 假设所有未排序的项目将出现在已经排序的列表中。

编辑:

根据要求,在这种特定情况下,这是 Foo 对象:

public partial class Erpstatuscodes
  {
    public string ProgramCode { get; set; }
    public string StatusCode { get; set; }
    public string StatusCodeDescription { get; set; }
    public string ShortDescription { get; set; }
    public string TestInstructions { get; set; }
    public string SampleType { get; set; }
    public string StatusType { get; set; }
  }

unsortedItems 将从 EntityFramework 中提取,但 priorityList 项将从配置文件中反序列化。

此外,为了澄清,这是使用 .NET Framework 4.8,而不是 .NET Core。

标签: c#

解决方案


你说Foo没有任何成员可以与之比较,所以我假设那Foo是一个class(不是 a struct)并且你依赖于对象引用相等(==Object.ReferenceEquals)),这就是你的priorityList.IndexOf(sortedItem)代码在 - 下所做的-hood,下面的代码应该在其中工作:

Dictionary<Foo,Int32> priorityListIndexes = priorityList
    .Select( ( foo, idx ) => ( foo, idx ) )
    .ToDictionary( t => t.foo, t => t.idx);

List<Foo> prioritisedItems = unsorteditems
    .Select( unsortedFoo => ( foo: unsortedFoo, ok: priorityListIndexes.TryGetValue( unsortedFoo, out Int32 idx ), idx: idx ) )
    .Where( t => t.ok )
    .OrderBy( t => t.idx )
    .Select( t => t.foo )
    .ToList();

请注意,一般来说,对 使用引用类型是个坏主意TKey,但在这种情况下,没关系。


这实际上可以简化为单个.Join(同样需要注意Foo的是,连接谓词可以接受引用相等):

List<Foo> prioritisedItems = Enumerable
    .Join<Foo>(
        outer           : priorityList.Select( ( foo, idx ) => ( foo, idx ) ),
        inner           : unsorteditems,
        outerKeySelector: t => t.foo,
        innerKeySelector: foo => foo,
        resultSelector  : ( left, right ) => ( left.idx, right )
    )
    .OrderBy( t => t.idx )
    .Select( t => t.foo )
    .ToList();

推荐阅读