2017-11-14 5 views
0

테이블에서 데이터를 가져올 필요가 있습니다. 다른 필드의 임의의 위치에 ID가있는 레코드를 제외하는 확장 메서드

은 테이블의 구조 :

ID  PackageID  DESC OriginalPackageID Status 
------------------------------------------------------- 
1   00A  Test  Null    P 

2   00B  xxxx  Null    P 

3   00A  test1  1    W 

내가 Status = P으로 레코드를 가져 오기 위해 확장 방법을 사용하여 LINQ 쿼리를 작성하고 싶지만 그 ID 기록의 존재하지 않습니다 'OriginalPackageID.

예를 들어 ID = 1 인 레코드는 Status = P이지만 1은 세 번째 레코드의 OriginalPackageID입니다. 따라서 첫 번째 기록은 제외되어야합니다. 두 번째 레코드 만 반환해야합니다.

답변

0

따라서 상태가 P이고 테이블의 OriginalPackageId 값이 레코드의 ID와 같은 요소가없는 모든 레코드를 테이블에서 원합니다.

IEnumerable<MyClass> table = ... 
var result = table 
    .Where(record => record.Status == P 
     && !table.Any(item => item.OriginalPackageId == record.Id)); 

이 효율적이지 않습니다, 모든 레코드에 대한 befause이 잠재적에 전체 표를 확인해야합니다 :

이 설명은 이미 나는 효율적인지 잘 모르겠어요하지만,이 작업을 수행하는 방법을 말한다 ID가 OriginalPackageId로 사용되지 않았는지 확인하십시오.

운 좋게도 레코드의 ID와 동일한 OriginalPackageId 값을 가진 레코드는 상관하지 않습니다. 따라서이 OriginalPackageId 값을 가진 레코드를 기억할 필요가 없습니다.

모든 레코드에서이 OriginalPackageId 값을 사용한다는 것을 기억하면됩니다.

먼저 사용 된 OriginalPackageIds를 HashSet<int> 개체에 넣으십시오. 이 경우 테이블 요소를 한 번 전달해야합니다.

IEnumerable<int> allOriginalPackageIds = table 
    .Select(record => record.OriginalPackageId); 
HashSet<int> usedPackageIds = new HashSet<int>(allOriginalPackageIds); 

HashSet의 생성자는 중복을 제거합니다.

이제 ID가 OriginalPackageID에서 사용되면 HashSet.Contains을 사용하여 조회 할 수 있습니다. 이것은 매우 빠른 기능입니다.

처럼 확장 기능은 다음과 같습니다 HashSet의는 O

public static IEnumerable<MyClass> ExtractOriginalItems(
    this IEnumerable<MyClass> table) 
{ 
    IEnumerable<int> allOriginalPackageIds = table 
     .Select(record => record.OriginalPackageId); 
    HashSet<int> usedPackageIds = new HashSet<int>(allOriginalPackageIds); 

    foreach(var record in table) 
    { 
     // return elements with status P and not ID in hashset: 
     if (record.Status == P && !usedPackageIds.Contains(record.Id)) 
     { 
      yield return record; 
     } 
    } 
} 

만들기 (1) 를 ForEach는 O (1)

관련 문제