No, Select
siempre produce un elemento de salida para cada elemento de entrada. No hay alternativa a eso. Podrías escribir fácilmente tu propio FilteredSelect
método de extensión, pero es más simple usar un Where
cláusula.
Alternativamente, use Process.GetProcesses()
para obtener una instantánea de todos los procesos y luego unirla a su colección de sesiones (o usar algo similar). Eso evitaría la trampa fea:
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);
O:
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;
Select
en Linq es el equivalente a Map
, mientras que Aggregate
es el equivalente a Reduce
. Map/Select es 1:1 de entrada a salida. Quieres usar Reduce
/Aggregate
si no hay una relación 1:1.
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;
});
}
Sobre la base de la publicación de John Skeet, este método de extensión me ha ahorrado innumerables líneas de código. El nombre encaja perfectamente Selectwhere . La lista de códigos a continuación es un método de extensión que puede usar.
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);
}
Uso:
entity.SelectWhere(e => /* returned element */, e => /* bool condition */);