列出LINQ中的唯一转换

时间:2013-11-14 14:32:10

标签: c# .net algorithm linq functional-programming

我有一个有序的实体列表。每个实体都有int UniqueKey属性。

我希望列表经历一个转换,使UniqueKey值变为唯一(假设存在重复)。这是通过查找重复项并逐步递增它们来完成的。

分步流程:

  1. 从索引1开始(我使用从零开始的索引编制)
  2. 如果以前的任何元素具有相同的UniqueId值,请在当前索引处增加值。
  3. 重复(2)直到之前的元素没有相同的UniqueId
  4. 向右移动一个元素
  5. 例如,{ 1, 1, 1, 3, 3, 8 }将执行以下步骤:

    1. { 1, 2, 1, 3, 3, 8 }:索引1递增
    2. { 1, 2, 2, 3, 3, 8 }:索引2递增
    3. { 1, 2, 3, 3, 3, 8 }:索引2再次递增
    4. { 1, 2, 3, 4, 3, 8 }:索引3递增
    5. { 1, 2, 3, 4, 4, 8 }:索引4递增
    6. { 1, 2, 3, 4, 5, 8 }:索引4再次递增
    7. 下面的代码以非常程序的方式执行上述算法:

      entities = entities.OrderBy(x => x.UniqueId);
      
      foreach (var entity in entities)
      {
          var leftList = entities.Take(entities.IndexOf(entity));
      
          while (leftList.Any(x => x.UniqueId == entity.UniqueId))
          {
              entity.UniqueId++;
          }
      }
      

      问题:是否可以在LINQ中实现这一点?

4 个答案:

答案 0 :(得分:1)

你的算法可以简化很多。只需迭代,如果Id低于前一个,则将其递增1。没有Linq,没有O(n ^ 2),只有O(n):

{ 1, 2, 1, 3, 3, 8 } : Index 1 incremented
{ 1, 2, 3, 3, 3, 8 } : Index 2 incremented
{ 1, 2, 3, 4, 3, 8 } : Index 3 incremented
{ 1, 2, 3, 4, 5, 8 } : Index 4 incremented

entities = entities.OrderBy(x => x.UniqueId).ToList();
for(int index = 1; index < entities.Count; index++)
{
    int previous = entities[index - 1].UniqueId;
    if (previous >= entities[index].UniqueId)
    {
        entities[index].UniqueId = previous + 1;
    }
}

答案 1 :(得分:0)

技术上是的:

var indexedEntities =
   entities.Select((e, i) => new { Entity = e, Index = i })
           .ToList();

indexedEntities.ForEach(ie =>
   ie.Entity.UniqueId =
      indexedEntities.Any(prev => prev.Index < ie.Index)
     && ie.Entity.UniqueId
        <= indexedEntities.TakeWhile(prev => prev.Index < ie.Index)
                          .Max(prev => prev.Entity.UniqueId)
        ? indexedEntities.TakeWhile(prev => prev.Index < ie.Index)
                         .Max(prev => prev.Entity.UniqueId) + 1
        : ie.Entity.UniqueId);

var result = indexedEntities.Select(ie => ie.Entity);

虽然请,为了爱IT中所有神圣的东西,不要,只是不要:)

答案 2 :(得分:0)

这并没有忠实地遵循您的算法,但它可能会给您想要的结果。 基本上将每个元素与下一个元素进行比较,并将后者的Id增加为比前者更多。

entities.OrderBy(e => e.Id)
    .Aggregate((e1, e2) => { if (e1.Id >= e2.Id) { e2.Id = e1.Id + 1; } return e2; });

答案 3 :(得分:0)

如果你急需一个linq解决方案,为什么不直接使用索引作为id。

entities.OrderBy(x => x.UniqueId).Select((x,i) => {
                                                     x.UniqueId = i;
                                                     return x;
                                                  }).ToArray();