我在一个已排序的数组上使用LINQ to Objects指令。我应该避免哪些操作,以确保数组的顺序不会改变?
我在一个已排序的数组上使用LINQ to Objects指令。我应该避免哪些操作,以确保数组的顺序不会改变?
我检查了System.Linq.Enumerable的方法,剔除了返回非IEnumerable结果的任何方法。我检查了每个方法的备注,以确定其结果顺序与源顺序的不同之处。
完全保留顺序。您可以通过索引将源元素映射到结果元素
保留顺序。元素被过滤或添加,但不重新排序。
破坏顺序 - 我们不知道期望的结果顺序。
明确重新定义顺序 - 使用这些来更改结果的顺序
根据某些规则重新定义顺序。
编辑:根据实现,我将Distinct移到了保留顺序。
private static IEnumerable<TSource> DistinctIterator<TSource>
(IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
{
Set<TSource> set = new Set<TSource>(comparer);
foreach (TSource element in source)
if (set.Add(element)) yield return element;
}
你在谈论SQL还是数组?换句话说,你正在使用LINQ to SQL还是LINQ to Objects?
LINQ to Objects操作符并不会实际改变它们的原始数据源 - 它们构建的序列实际上是由数据源支持的。唯一更改顺序的操作是OrderBy/OrderByDescending/ThenBy/ThenByDescending - 即使是这些操作,对于相同排序的元素来说也是稳定的。当然,许多操作会过滤掉一些元素,但返回的元素将保持相同的顺序。
如果转换为不同的数据结构,例如通过ToLookup或ToDictionary,我不认为此时会保留顺序 - 但这也有些不同。 (我相信查找的值映射到相同的键的顺序被保留了。)
GroupBy
后跟SelectMany
才能按键分组,但不是按升序键顺序...它们将按键最初出现的顺序排列。 - Jon Skeetlist<x> {a b c d e f g}
中,如果 c、d 和 e 都具有相同的键,则结果序列将包含 c、d 和 e 按顺序紧挨在一起。我似乎找不到一个明确的基于 MS 的答案。 - PaulustriousToDictionary()
只是不对顺序做出承诺,但实际上会保持输入顺序(直到你从中删除某些内容)。我并不是说要依赖这一点,但“混乱”似乎不准确。 - TimoSelect
、Where
或GroupBy
返回的元素顺序。但是,对于像ToDictionary
或Distinct
这样本质上无序的事物,情况并非如此。IGrouping<TKey, TElement>
对象按照每个分组的第一个键在源中产生的元素的顺序进行生成。组内的元素按它们在源中出现的顺序生成。IQueryable
扩展方法(其他LINQ提供程序),这并不一定正确。mysqlresult.OrderBy(e=>e.SomeColumn)
//original sorting order lost
var inv2 = db.Inventories
.GroupBy(l => l.VendorFullSKU)
.Select(cl => new Inventory2
{
VariantID = cl.FirstOrDefault() == null ? 0 : cl.FirstOrDefault().VariantID,
Quan = cl.Sum(c => c.Quan),
Color = cl.FirstOrDefault() == null ? "" : cl.FirstOrDefault().Color
});
//original sorting order restored
var bl = (from pv in db.ProductVariants
join inv in inv2 on pv.VariantID equals inv.VariantID
orderby inv.VariantID, inv.Color //sort
select inv.Color
).ToList();
//remove duplicates while preserving original sort order
var colorsDistinct = new List<string>();
foreach (var item in bl)
{
if (!colorsDistinct.Contains(item))
colorsDistinct.Add(item);
}