从列表中获取优先项,并将其插入到给定位置c#

时间:2018-10-01 14:27:35

标签: c# lambda

我有一个50个排序项目(例如)的列表,其中几个项目是优先项目(假设它们的标志设置为1)。

默认情况下,我必须首先显示最新的项目(基于日期),但是优先级项目应该出现在一些“ x”记录之后。像下面一样

索引0:项目
索引1:项目
索引2:优先项(从此位置插入优先项)
索引3:优先项
索引4:优先项目
索引5:项目
索引6:项目

插入优先项的索引“ x”是预定义的。

为此,我正在使用以下代码

这些是我排序的50个项目

var list= getMyTop50SortedItems();

获取所有优先项并将其存储在另一个列表中

var priorityItems = list.Where(x => x.flag == 1).ToList();

从主列表中滤除优先项

list.RemoveAll(x => z.flag == 1);

在主列表中的给定位置插入优先项

list.InsertRange(1, priorityRecords);

此过程正确完成了工作,并给了我预期的结果。但是不确定是正确的方法还是有更好的方法(考虑性能)? 请提供您的建议。

另外,考虑到记录数从50增加到100000(任意数量),性能如何影响我进行许多操作(过滤,删除,插入)。

更新:如何使用 IQueryable 减少列表上的操作数量。

3 个答案:

答案 0 :(得分:2)

根据InsertRange上的文档:

  

此方法是O(n * m)运算,其中n是   要添加的元素,而m为Count。

n * m不太好,所以我将使用LINQ的Concat方法从三个较小的列表中创建一个全新列表,而不是修改现有列表。

var allItems = getMyTop50();
var topPriorityItems = list.Where(x => x.flag == 1).ToList();
var topNonPriorityItems = list.Where(x => x.flag != 1).ToList();

var result = topNonPriorityItems
    .Take(constant)
    .Concat(topPriorityItems)
    .Concat(topNonPriorityItems.Skip(constant));

我不确定Concat的{​​{1}},SkipTake方法有多快,但是我敢打赌它们不会比O( n)。

答案 1 :(得分:2)

似乎您实际上要解决的问题只是对项目列表进行排序。如果是这种情况,则不必担心删除优先项并在正确的索引处重新插入优先项,只需要弄清楚排序功能即可。这样的事情应该起作用:

// Set "x" to be whatever you want based on your requirements --
// this is the number of items that will precede the "priority" items in the
// sorted list
var x = 3;

var sortedList = list
   .Select((item, index) => Tuple.Create(item, index))
   .OrderBy(item => {
       // If the original position of the item is below whatever you've 
       // defined "x" to be, then keep the original position
       if (item.Item2 < x) {
          return item.Item2;
       } 

       // Otherwise, ensure that "priority" items appear first
       return item.Item1.flag == 1 ? x + item.Item2 : list.Count + x + item.Item2;
}).Select(item => item.Item1);

您可能需要根据要执行的操作进行微调,但这似乎比从多个列表中删除/插入要简单得多。

编辑:忘记了.OrderBy并没有提供该项目原始索引的重载;更新了答案,将项目包装在包含原始索引的元组中。不像原始答案那么干净,但是它仍然可以正常工作。

答案 2 :(得分:0)

这可以通过使用linq-to-objects对原始集合进行一次枚举来完成。 IMO还可以根据您定义的原始要求清楚地阅读该内容。

首先,定义我们将要归类的“存储桶”:为清楚起见,我喜欢在此处使用枚举,但是您也可以只使用整数。

enum SortBucket
{
  RecentItems = 0,
  PriorityItems = 1,
  Rest = 2,
}

然后,我们将定义将特定项目分类为“存储桶”的逻辑:

private static SortBucket GetBucket(Item item, int position, int recentItemCount)
{
  if (position <= recentItemCount)
  {
    return SortBucket.RecentItems;
  }
  return item.IsPriority ? SortBucket.PriorityItems : SortBucket.Rest;
}

然后是一个非常简单的linq-to-objects语句,首先将其分类到我们定义的存储桶中,然后再按原始位置进行分类。作为扩展方法编写:

static IEnumerable<Item> PrioritySort(this IEnumerable<Item> items, int recentItemCount)
{
  return items
    .Select((item, originalPosition) => new { item, originalPosition }) 
    .OrderBy(o => GetBucket(o.item, o.originalPosition, recentItemCount))
    .ThenBy(o => o.originalPosition)
    .Select(o => o.item);
}