2012-09-21 3 views
2

특정 필드로 개체 목록을 그룹화하려고합니다.목록을 주문했지만 인덱스와 필드에 계속 액세스 할 수 있습니다.

는 나중에, 나는 다음과 같이이 목록을 사용해야합니다 내가 말할 수 있도록

for(i=0; i< list.Count; i++) 
{ 
    if(i == 0) 
    continue; 

    if (list[i].property != list[i-1].property) 
    dosomething; 
} 

내가 루프를 할 필요가 "만약이 일이 달랐다 직전 항목의 특성 ...

목록을 정렬하려고 할 때 문제가 발생합니다 .list.GroupBy를 실행하면 목록 항목의 멤버에 액세스 할 수 없습니다. 목록을 작성한 경우 주문을 ienumerable로 설정해야합니다. 따라서 ienumerables가 목록 색인에서 작동하지 않기 때문에 for 루프를 사용할 수 없습니다.

isr foreach 루프에서이 기능을 구현하는 방법 (인덱스를 참조하지 않고)? 그렇지 않다면 목록을 ienumerable로 설정할 필요가없는 다른 방법으로 주문할 수 있습니까?

+4

'if (i == 0) continue;가 아닌'i'를'1'로 초기화하지 않는 이유는 무엇입니까? – Servy

답변

3

네 가지 옵션 :

  • 사용 OrderBy 다음 ToList은 정렬 된 목록을 얻을 수 있습니다. 그런 다음 기존 코드를 사용할 수 있지만 0에서 시작하여 첫 번째 반복에서 즉시 중단하지 않고 루프를 1에서 시작하는 것이 좋습니다.
  • 사용 OrderBy 다음 Zip :이 불행하게도, 두 번 입력을 정렬 할 것을

    var ordered = input.OrderBy(...); 
    var zipped = ordered.Zip(ordered.Skip(1), 
             (Previous, Current) => new { Previous, Current }); 
    
    foreach (var pair in zipped) 
    { 
        if (pair.Previous.Property == pair.Current.Property) 
        { 
         ... Whatever you want to do 
        } 
    } 
    

    참고. 그 것을 회피 할 수있는 방법은 없습니다 (ToList 또는 무엇이든 부를 필요없이). "self-zip"확장 방법을 쓰는 것은 그리 어렵지 않을 것입니다.

  • 사용 OrderBy과 "이전의 속성을"유지 :

    var ordered = input.OrderBy(...); 
    // This is like using foreach, but with a simple way to get the 
    // first item 
    using (var iterator = ordered.GetEnumerator()) 
    { 
        if (!iterator.MoveNext()) 
        { 
         return; // Or whatever. No items! 
        } 
        var previousProperty = iterator.Current.Property; 
        while (iterator.MoveNext()) 
        { 
         var currentProperty = iterator.Current.Property; 
         if (previousProperty == currentProperty) 
         { 
          ... Whatever you want to do 
         } 
         previousProperty = currentProperty; 
        } 
    } 
    
  • 정렬 목록에서 장소를 List<T>.Sort

+0

'zip' 코드가 정렬을 두 번 수행합니다. 이는 주문하고 새 목록을 다시 채우는 것보다 훨씬 많은 작업입니다. (목록/배열이 있으면 코드 대신 zip을 사용할 수 있습니다.) – Servy

+0

@Servy : 네, 편집하고있었습니다. 이미 배열이있을 때 Zip을 사용하는 것이 가치 있다고 생각하지 않습니다. –

+0

많은 일을하고 싶다면 현재의 아이템과 이전의 셀렉터에 대한 파라미터로 제공되는'Select'에 새로운 오버로드를 추가하는 것이 좋을 것입니다. 나는 내 용도로 쓸 필요가 있다고 생각한다. – Servy

0

당신을 사용하여 (즉, 최대 다른 엉망 아무것도 않는 경우) 루프 바로 앞에 myitem previous을 정의 할 수 있으며 (myitem은 목록에서 동일한 유형 임) 각 목록의 끝에 previous을 현재 항목으로 설정하십시오. 이렇게하면 previous에 처음으로 값이 없기 때문에 null인지 확인하십시오.

0

이것은 Skeet의 옵션 중 하나의 반복입니다. 수표를주세요.

ForEach에는 색인이 필요하지 않습니다. ForEach를 사용하여 목록에서 항목을 삭제할 수 없습니다.

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<SortMe> SortMes = new List<SortMe>(); 

     SortMes.Add(new SortMe("aaa")); 
     SortMes.Add(new SortMe("bbb")); 
     SortMes.Add(new SortMe("ccc")); 
     SortMes.Add(new SortMe("aaa")); 
     SortMes.Add(new SortMe("bbb")); 
     SortMes.Add(new SortMe("ccc")); 
     SortMes.Add(new SortMe("ccc")); 
     SortMes.Add(new SortMe("bbb")); 
     SortMes.Add(new SortMe("aaa")); 
     SortMes.Add(new SortMe("ccc")); 
     SortMes.Add(new SortMe("bbb")); 
     SortMes.Add(new SortMe("aaa")); 

     SortMe SortMeLast = null; 

     foreach (SortMe SortMeCurrent in SortMes.OrderBy(x => x.Name)) 
     { 
      Console.WriteLine(" Current  " + SortMeCurrent.Name); 
      if (SortMeLast != null) 
      { 
       if (SortMeCurrent.Name != SortMeLast.Name) 
       { 
        // do something 
        Console.WriteLine("Do Something"); 
       } 
      } 
      SortMeLast = SortMeCurrent; 
     } 
     Console.ReadLine(); 
    } 
} 
public class SortMe 
{ 
    public string Name { get; set; } 
    public SortMe(string name) { Name = name; } 
} 
관련 문제