Reza Hatami
Reza Hatami

Reputation: 102

Skip from penultimate item in the IEnumerable

I have a IEnumerable (not List) like the following list :

A,B,C,D,E

With the command below, I will skip the last item (E) :

items_split.Take(items_split.Count() - 1);  //output : A,B,C,D

And with the command below, I will skip the first item (A) :

items_split.Skip(1); //output : B,C,D,E

how can i skip the penultimate item in the list? (desired result is A,B,C,E)

Note : not the last, but immediately before the last.

Upvotes: 3

Views: 212

Answers (4)

Avner Shahar-Kashtan
Avner Shahar-Kashtan

Reputation: 14700

This option takes advantage of the Where overload that takes an index, and use it to skip the next-to-last index.

var count = items_split.Count();
items_split.Where((item, index) => index != count -2)

Note, though, that this will call Count to get the total count, which will result in an iteration of the IEnumerable, and then a second iteration with Where. You might want to get a concrete, materialized collection first.

This might seem to defeat the point of using an IEnumerable in the first place, but remember, if your logic asks for the next-to-last, it means that you have to get to the end of the collection to know that it's the next to last.

Upvotes: -2

Dmitrii Bychenko
Dmitrii Bychenko

Reputation: 186698

Let's exploit the fact that items_split is a List<T> - we can use Count:

var result = items_split
  .Where((value, index) => index != items_split.Count() - 2);

In general case (when items_split is IEnumerable<T> only Count can be too expencive or even misleasing e.g. if you query a file which can be changed after Count):

public static IEnumerable<T> ExcludePenultimate<T>(IEnumerable<T> source) {
  if (null == source)
    throw new ArgumentNullException(nameof(source));

  Queue<T> queue = new Queue<T>();

  foreach (var item in source) {
    queue.Enqueue(item);

    if (queue.Count > 2) 
      yield return queue.Dequeue();
  }

  if (queue.Count > 2)
    yield return queue.Dequeue();

  if (queue.Count == 2)
    queue.Dequeue();

  yield return queue.Dequeue();
}

and then

var result = ExcludePenultimate(items_split);

Upvotes: 4

Lucifer
Lucifer

Reputation: 1594

You can try another approach with List.RemoveAt(int) where int is index you want to remove.

items_split.RemoveAt(items_split.Count - 2);

Upvotes: 1

fubo
fubo

Reputation: 45947

Another approach with Skip() and Take()

List<char> items = new List<char>() { 'A', 'B', 'C', 'D', 'E' };
var result =  items.Take(items.Count() - 2).Concat(items.Skip(items.Count() - 1));

Upvotes: 3

Related Questions