2013-11-14 1 views
0

주문 된 엔티티 목록이 있습니다. 각 엔티티에는 int UniqueKey 속성이 있습니다.LINQ의 고유 한 변형 목록을 나열하십시오.

목록을 변형하여 UniqueKey 값을 고유하게 만듭니다 (중복이 있다고 가정). 이것은 중복을 찾아 점진적으로 증가시킴으로써 이루어진다.

단계별 프로세스 : 인덱스 1 에서

  1. 시작 이전의 요소가 같은 UniqueId 값이있는 경우
  2. , 값을 증가 (I는 제로 기반 색인을 사용하고 있습니다) 현재 색인에서.
  3. 반복 (2) 더 이전의 요소가 같은 UNIQUEID에게
  4. 이동이 없을 때까지 { 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 } : Ind 지수 3
  4. { 1, 2, 3, 4, 4, 8 } 증분 : 예 2 또
  5. { 1, 2, 3, 4, 3, 8 } 증분 인덱스 4
  6. { 1, 2, 3, 4, 5, 8 }
  7. 증분 : 인덱스 4를 다시 증가

아래의 코드는 매우 절차 적 방법으로 전술 한 알고리즘을 수행

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에서이를 구현할 수 있습니까? ?

+1

왜 이것을 LINQ에 구현하고 싶습니까?귀하의 알고리즘은 현재의 모양이 분명하다고 생각합니다. 확실히 속도를 높여 (가독성을 떨어 뜨릴 수는 있지만) LINQ를 사용하면이 알고리즘의 속도가 느려지고 판독이 어려워집니다. LINQ가 황금 망치가되어서는 안됩니다 ... –

+1

이 정확한 알고리즘을 사용해야합니까, 아니면 모든 ID가 고유하게 만들어지는 알고리즘을 사용할 수 있습니까? LINQ를 사용하려면 각 항목에 고유 한 ID를 부여하는 것이 좋습니다. – Servy

+1

쿼리가 아닌 의미 체계가있는 작업에 LINQ를 사용합니다 (http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx). 명령형 코드 만 사용하면 더 명확하고 간단 해집니다. – Vlad

답변

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 신성한 모두의 사랑을 위해, 단지이 충실히 알고리즘을 따르지 않는

+0

'Where's를'TakeWhile'로 대체해야합니다 – Servy

+0

@Servy 정말이 괴물을 최적화하는 것에 대해 생각해 보셨습니까? 충분히 공정하고 업데이트 됨 : – decPL

0

을 :)하지 마십시오, 그러나 그것은 당신에게 당신이 원하는 결과를 줄지도 모릅니다. 기본적으로 각 요소를 다음 요소와 비교하고 후자의 ID를 이전 요소보다 하나 더 늘립니다.

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

이것은 아무것도하지 않습니다. 먼저 OrderBy를 수행하고 이전 요소가 다음 요소보다 큰 경우에만 작업을 수행합니다. 혹시> = 대신에 = 의미하셨습니까? – decPL

+0

예 - 고마워요 :-) – Rob

+0

@ 로브 : 오, 집계, 내 잘못, 미안. 당신 말이 맞아요. – Vlad

1

알고리즘이 단순해질 수 있습니다. 그냥 반복하고 ID가 이전보다 낮 으면 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; 
    } 
} 
0

그냥 ID와 인덱스를 사용하지 왜 LINQ 솔루션에 대한 절망합니다.

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