我有一个包含 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来减少列表中的操作数量。
根据InsertRange
的文档:
此方法是一个 O(n * m( 操作,其中 n 是 元素要添加,m 是计数。
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));
我不确定List<T>
的Concat
、Skip
和Take
方法有多快,但我敢打赌它们并不比O(n(慢。
似乎您实际要解决的问题只是对项目列表进行排序。如果是这种情况,您无需担心删除优先级项目并将它们重新插入正确的索引,您只需要弄清楚您的排序排序函数。这样的事情应该有效:
// 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
不提供提供项目原始索引的重载;更新了答案以将项目包装在包含原始索引的元组中。不像原始答案那么干净,但它应该仍然有效。
这可以使用 linq-to-对象的原始集合的单个枚举来完成。IMO 根据您定义的原始要求,这也读得很清楚。
首先,定义我们将要分类的"桶":为了清楚起见,我喜欢在这里使用枚举,但您也可以只使用 int。
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);
}