Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can IEnumerable.Select() skip an item?

Tags:

c#

ienumerable

I have this function:

public IEnumerable<string> EnumPrograms() {
    return dev.AudioSessionManager2.Sessions.AsEnumerable()
        .Where(s => s.GetProcessID != 0)
        .Select(s => {
            try {
                return Process.GetProcessById((int)s.GetProcessID).ProcessName;
            }
            catch (ArgumentException) {
                return null;
            }
        });
}

The try..catch is necessary since there may be sessions with a PID that doesn't exist anymore. I'd like to skip them. Is there a way to do this from the Select callback or do I need to add a new Where condition that skips null values?

like image 322
ThiefMaster Avatar asked Dec 08 '13 13:12

ThiefMaster


People also ask

How to skip elements from list in c#?

ToList(); list = list. Skip(0). Take(10);

How to use Take and skip in c#?

The Take operator is used to return a given number of elements from an array and the Skip operator skips over a specified number of elements from an array. Skip, skips elements up to a specified position starting from the first element in a sequence.

How to use skip and Take in Linq?

In this article I am going to explain the Take and Skip operators in LINQ to SQL. The Take operator is used to return a given number of rows from a database table and the Skip operator skips over a specifed number of rows in a database table.

What does Take do in c#?

The Take() method extracts the first n elements (where n is a parameter to the method) from the beginning of the target sequence and returns a new sequence containing only the elements taken.


2 Answers

No, Select always yields one output element for each input element. There's no alternative to that. You could easily write your own FilteredSelect extension method - but it's simpler just to use a Where clause.

Alternatively, use Process.GetProcesses() to get a snapshot of all processes, and then join that to your sessions collection (or use something similar). That would avoid the ugly catch:

var sessionProcessIds = new HashSet<int>(dev.AudioSessionManager2.Sessions
                                            .AsEnumerable()
                                            .Select(x => x.GetProcessId)
                                            .Where(pid => pid != 0));
var processes = Process.GetProcesses();
var sessionProcessNames = processes.Where(p => sessionProcessIds.Contains(p.Id))
                                   .Select(p => p.ProcessName);

Or:

var names = from session in dev.AudioSessionManager2.Sessions.AsEnumerable()
            let pid = session.GetProcessId
            where pid != 0
            join process in Process.GetProcesses() on pid equals process.Id
            select process.ProcessName;
like image 98
Jon Skeet Avatar answered Oct 17 '22 11:10

Jon Skeet


Building on John Skeet's post this extension method has saved me countless lines of code. The name fits perfectly SelectWhere. The code listing below is an Extension method you can use.

    public static IEnumerable<TResult> SelectWhere<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector, Func<TSource, bool> predicate)
    {
        foreach (TSource item in source)
            if (predicate(item))
                yield return selector(item);
    }

Usage:

entity.SelectWhere(e => e.FirstName, e => e.Age>25);
like image 6
Rax Avatar answered Oct 17 '22 12:10

Rax