我有一个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 减少列表上的操作数量。
答案 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}},Skip
和Take
方法有多快,但是我敢打赌它们不会比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);
}