Can IEnumerable.Select() skip an item?
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;
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);
Select
in Linq is the equivalent to Map
, while Aggregate
is the equivalent to Reduce
. Map/Select is 1:1 input to output. You want to use Reduce
/Aggregate
if there is not a 1:1 relationship.
public IEnumerable<string> EnumPrograms() {
return dev.AudioSessionManager2.Sessions.AsEnumerable()
.Where(s => s.GetProcessID != 0)
.Aggregate(new List<string>(), (acc, s) => {
try {
var proc = Process.GetProcessById((int)s.GetProcessID).ProcessName;
acc.Add(proc);
} catch (ArgumentException) { }
return acc;
});
}