2008-10-26 2 views
1

C# 모음 문자열이 있습니다. 각 문자열은 페이지에 나타날 수있는 문장입니다. 또한 int의 컬렉션 인 페이지 나누기 모음이 있습니다. 문자열 컬렉션이 새 페이지로 분할되는 인덱스를 나타냅니다.LINQ 및 C#을 사용하여 하위 모음을 선택하기위한 알고리즘/패턴

예 : 페이지 나누기의 컬렉션 (10)의 값, 20, 30와 INT 년대의 수집 될 수 있도록 문자열 컬렉션에서 각 10 개 항목 2

가 그렇다면 ... 페이지입니다 문자열 페이지가 있으면 페이지 나누기 컬렉션에 1 개의 항목이 있고 1 페이지가 있으면 페이지 나누기 모음에 항목이 없을 것입니다.

나는 다음과 같은 기능을 만들려고 오전 : 단일 및 두 페이지 고려해야

List<string> GetPage(List<string> docList, List<int> pageBreakList, int pageNum) 
{ 
    // This function returns a subset of docList - just the page requested 
} 

나는이 기능을 쓰기에 약간의 찌르기를 촬영했습니다 및 경우 복잡한 함께 올라오고 계속하고 문을 전환 문서 및 페이지 번호가 범위를 벗어나 요청됩니다 (예 : 페이지 번호가 페이지 수보다 크면 마지막 페이지가 반환되고 페이지 번호가 0보다 작 으면 첫 번째 페이지가 반환 됨).

이 문제로 인해 어려움을 겪었습니다.이 유형의 하위 집합 쿼리를 처리 할 수있는 잘 알려진 패턴이나 알고리즘이 있습니까?

답변

2

"순수한"Linq는이 문제에 적합하지 않습니다. 가장 적합한 방법은 List (T)의 메서드와 속성에 의존하는 것입니다. 많은 특별한 경우는 없습니다.

//pageNum is zero-based. 
List<string> GetPage(List<string> docList, List<int> pageBreaks, int pageNum) 
{ 

    // 0 page case 
    if (pageBreaks.Count != 0) 
    { 
    return docList; 
    } 

    int lastPage = pageBreaks.Count; 

    //requestedPage is after the lastPage case 
    if (requestedPage > lastPage) 
    { 
    requestedPage = lastPage; 
    } 


    int firstLine = requestedPage == 0 ? 0 : 
     pageBreaks[requestedPage-1]; 
    int lastLine = requestedPage == lastPage ? docList.Count : 
     pageBreaks[requestedPage]; 

    //lastLine is excluded. 6 - 3 = 3 - 3, 4, 5 

    int howManyLines = lastLine - firstLine; 

    return docList.GetRange(firstLine, howManyLines); 
} 

.Count 속성을 linq의 .Count() 메서드로 바꾸고 싶지 않습니다. .GetRange() 메소드를 linq의 .Skip (n) .Take (m) 메소드로 대체하지 않으려합니다. 다른 컬렉션으로 이러한 컬렉션을 투사하기를 원한다면

Linq에이 더 잘 맞는 것 :

IEnumerable<Page> pages = 
    Enumerable.Repeat(0, 1) 
    .Concat(pageBreaks) 
    .Select 
    (
    (p, i) => new Page() 
    { 
     PageNumber = i, 
     Lines = 
     docList.GetRange(p, ((i != pageBreaks.Count) ? pageBreaks[i] : docList.Count) - p) 
    } 
); 
+0

왜 GetRange()가 Skip() 및 Take()보다 나은 옵션인지 자세히 설명해 주시겠습니까? –

+1

GetRange는 List의 내부 구현을 활용합니다. Skip/Take는 IEnumerable (열거를 포함)의 계약을 사용합니다. List에 백만 개의 요소가 있으면 GetRange를 사용하여 950,000에서 950,010 사이의 요소를 더 빠르게 얻을 수 있습니다. –

+0

"'pageBreaks.Count! = 0'" 'pageBreaks.Count == 0'을 의미합니까? 'pageBreaks.Any()'가 일반적으로 바람직합니다. 계산이 필요하지 않습니다. –

4

페이지 나누기 목록이 무엇인지 확실하지 않습니다. 나는 이런 식으로 생각할 것이다. 문자열 모음, 페이지 번호 및 페이지 크기. 그렇다면 다음과 같이 할 수 있습니다 :

List<string> strings = ... 
int pageNum = ... 
int pageSze = ... 

if (pageNum < 1) pageNum = 1; 
if (pageSize < 1) pageSize = 1; 

List<string> pageOfStrings = strings.Skip(pageSize*(pageNum-1)).Take(pageSize).ToList(); 

귀하의 의견에 따라 페이지 당 페이지 수가 다른 경우 다음과 같이 시도하십시오. 가장자리 상태 검사를 조정해야 할 수도 있습니다 ...

List<string> strings = ... 
List<int> sizes = ... 

int pageNum = ... 
int itemsToSkip = 0; 
int itemsToTake = 1; 

if (pageNum > 1) 
{ 
    sizes.Take(pageNum - 2).Sum(); 

    if (pageNum <= sizes.Count) 
    { 
     itemsToTake = sizes[pageNum-1] 
    } 
{ 

List<string> pageOfStrings = strings.Skip(itemsToSkip).Take(itemsToTake); 
+0

그래,이 대답을하려고 했어요. Linq의 페이징 패턴은 Skip과 Take 메소드에 의해 구현된다. i가 페이지의 항목 수이고 j가 보려는 페이지 번호 인 경우 i * (j-1) 항목을 건너 뛰고 i를 가져옵니다. – Will

+0

좋은 답변이지만 페이지 당 줄 수는 각 페이지마다 다를 수 있으므로 새 페이지를 시작하는 각 줄의 색인 위치는 페이지 나누기 모음입니다. – Guy

+0

이 가변 페이지 솔루션에는 몇 가지 장점이 있습니다. 첫 페이지가 도청되어 과제가 누락되었습니다. –

관련 문제