LINQ 및 C#을 사용하여 하위 수집을 선택하기위한 알고리즘/패턴
-
04-07-2019 - |
문제
C# 문자열 컬렉션이 있습니다. 각 문자열은 페이지에 표시 될 수있는 문장입니다. 또한 INT 모음 인 페이지 브레이크 모음이 있습니다. 문자열 모음이 새 페이지로 분할되는 인덱스를 나타냅니다.
예 : 문자열 컬렉션의 각 10 개 항목은 페이지이므로 페이지 브레이크 모음은 값이 10, 20, 30의 int 모음이 될 것입니다.
따라서 문자열의 2 페이지가 있으면 페이지 브레이크 컬렉션에 1 개의 항목이 있고 1 페이지가 있으면 페이지 브레이크 컬렉션에 항목이 0이됩니다.
다음과 같은 기능을 만들려고합니다.
List<string> GetPage(List<string> docList, List<int> pageBreakList, int pageNum)
{
// This function returns a subset of docList - just the page requested
}
이 기능을 작성하는 데 약간의 찌르기를했고 단일 및 2 페이지 문서와 페이지 번호가 범위 밖에서 요청되는 단일 및 2 페이지 문서와 페이지 번호를 고려하여 복잡한 if 및 스위치 명세서를 계속 생각해냅니다 (예 : 페이지 번호가있는 경우 마지막 페이지를 반환해야합니다. 페이지 수보다 큰 경우 페이지 번호가 0 이하인 경우 첫 페이지).
이 문제와의 투쟁은 다음과 같이 질문하게됩니다.이 유형의 서브 세트 쿼리를 해결하기 위해 잘 알려진 패턴이나 알고리즘이 있습니까?
해결책
"순수한"LINQ는이 문제에 적합하지 않습니다. 가장 적합한 것은 목록 (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)
}
);
다른 팁
페이지 브레이크 목록이 무엇인지 확실하지 않습니다. 나는 이런 식으로 생각할 것이다. 문자열 모음, 페이지 번호 및 페이지 크기. 그런 다음 다음과 같은 작업을 수행 할 수 있습니다.
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 );