Алгоритм/шаблон выбора подколлекций с использованием LINQ и C#

StackOverflow https://stackoverflow.com/questions/238340

Вопрос

У меня есть коллекция строк C#.Каждая строка представляет собой предложение, которое может появиться на странице.У меня также есть коллекция разрывов страниц, которая представляет собой коллекцию целых чисел.представляющий индекс, в котором коллекция строк разбивается на новую страницу.

Пример:Каждые 10 элементов в коллекции строк представляют собой страницу, поэтому коллекция разрывов страниц будет коллекцией целых чисел со значениями 10, 20, 30....

Таким образом, если есть 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
}

Я предпринял несколько попыток написать эту функцию и продолжаю придумывать сложные операторы if и switch, чтобы учитывать одно- и двухстраничные документы и номера страниц, запрашиваемые за пределами диапазона (например,последняя страница должна быть возвращена, если номер страницы больше количества страниц, и первая страница, если номер страницы равен 0 или меньше).

Моя борьба с этой проблемой заставляет меня задать вопрос:Существует ли хорошо известный шаблон или алгоритм для решения этого типа подмножества запросов?

Это было полезно?

Решение

«Чистый» 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 методом .Count() linq.Вы не хотите заменять метод .GetRange() методами .Skip(n).Take(m) linq.

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 );
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top