Получить n (часть) объектов из списка объектов, начиная с n индекса - PullRequest
2 голосов
/ 30 апреля 2019

У меня есть список из n объектов.Я хочу получить максимум n элементов (-n предыдущих элементов и n + следующих элементов), начиная с выбранного индекса.Я хочу метод для этого, в котором я предоставляю список с определенными параметрами.

Как я могу добиться этого в C #?

Первый пример:
intselectedIndex = 5
int itemsToTake = 4 (2 предыдущих и 2 следующих)
Возвращенный список = 3-4-5-6-7

Второй пример:
int selectedIndex = 1
int itemsToTake = 4 (взять 1 предыдущий и 3 следующий, потому что список начинается с 0)
Возвращенный список = 0-1-2-3-4

Iуже попробовал комбинацию list.skip (). take (), только это не очень хорошо.

Пример:

nextIndex = nextIndex - prevIndex + 1;
return List.Skip (prevIndex) .Take (nextIndex) .ToList ();

Ответы [ 5 ]

1 голос
/ 01 мая 2019

Неэффективный, но визуально эстетический способ сделать это:

public static IEnumerable<T> Nearby<T>(this IEnumerable<T> source,
    int selectedIndex, int itemsToTake)
{
    var left = source.Take(selectedIndex).Reverse().Take(itemsToTake / 2).Reverse();
    var middle = source.ElementAt(selectedIndex);
    var right = source.Skip(selectedIndex).Skip(1).Take(itemsToTake / 2);
    return left.Append(middle).Concat(right);
}

Пример использования:

var source = Enumerable.Range(0, 10);
Console.WriteLine($"Result: {String.Join(", ", source.Nearby(5, 5))}");

Выход:

Результат: 3, 4, 5, 6, 7

1 голос
/ 30 апреля 2019

Skip + Take должно работать нормально, попробуйте это:

int firstIndex = selectedIndex - itemsToTake / 2;
firstIndex = firstIndex < 0 ? 0 : firstIndex;
return list.Skip(firstIndex).Take(itemsToTake);
0 голосов
/ 01 мая 2019
public static IEnumerable<T> Nearby<T>(IEnumerable<T> source, int selectedIndex, int itemsToTake)
{
  itemsToTake = ((itemsToTake/2)*2)+1;
  Queue<T> queue = new Queue<T>();
  bool foundItem = false;
  int afterItemCount = 0;
  int recommendedAfterItemCount = itemsToTake/2;
  foreach(var pair in source.Select((t, i) => new {t, i}))
  {
    T t = pair.t;
    int i = pair.i;

    queue.Enqueue(t);
    if (itemsToTake < queue.Count) queue.Dequeue();

    if (i == selectedIndex) foundItem = true;
    else if (foundItem) afterItemCount += 1;

    bool enoughItems = queue.Count == itemsToTake;
    bool enoughAfterItems = recommendedAfterItemCount <= afterItemCount;
    if (enoughItems && enoughAfterItems) break;

  }
  foreach(T t in queue)
  {
    yield return t;
  }
}
0 голосов
/ 30 апреля 2019

Вам необходимо обработать особый случай, когда selectedIndex - itemsToTake / 2 меньше 0:

public static List<T> Take<T>(this List<T> list, int selectedIndex, int itemsToTake) {
    if (selectedIndex - n / 2  < 0) {
        return list.Take(itemsToTake + 1).ToList();
    }
    return list.Skip(selectedIndex - itemsToTake / 2).Take(itemsToTake +1).ToList();
}
0 голосов
/ 30 апреля 2019

Сначала убедитесь, что список содержит достаточно элементов:

if(itemsToTake  + 1 > List.Count)
    return List.ToList(); //copy the list

Первый индекс, который вы хотите взять (без учета границ последовательности):

var firstIndex = selectedIndex - itemsToTake  / 2;

Соответствующим последним индексом будет firstIndex + n.

Затем убедитесь, что диапазон действителен

if(firstIndex < 0) 
    firstIndex = 0;
if(firstIndex + nitemsToTake >= List.Count)
    firstIndex = List.Count - 1 - itemsToTake ;

И, наконец, сделайте, как вы пытались:

return List.Skip(firstIndex).Take(itemsToTake  + 1).ToList();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...