score:1

Accepted answer

An inefficient but visually aesthetic way of doing it:

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);
}

Usage example:

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

Output:

Result: 3, 4, 5, 6, 7

score:0

First, make sure that the list contains enough elements:

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

The first index you want to take is (not considering sequence borders):

var firstIndex = selectedIndex - itemsToTake  / 2;

The corresponding last index would be firstIndex + n.

Then, make sure that the range is valid

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

And finally do as you tried:

return List.Skip(firstIndex).Take(itemsToTake  + 1).ToList();

score:0

You need to handle the special case of when selectedIndex - itemsToTake / 2 is less than 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();
}

score:1

Skip + Take should work fine, try this:

int firstIndex = selectedIndex - itemsToTake / 2;
firstIndex = firstIndex < 0 ? 0 : firstIndex;
return list.Skip(firstIndex).Take(itemsToTake);

score:0

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;
  }
}

Related Articles