我有一个数据结构,其中“模块包含单元”和“单元包含节”,并从模块列表中查找第一个包含至少一个单元的模块,该单元包含至少一个节,并且我想做一些事情以及模块,单位和部分。
我最初尝试使用modules.Find()
,但是它只能告诉我第一个非空模块是什么,因此我必须两次查找单元:
var module = modules.Find(m => m.Units.Exists(u => u.Sections.Count > 0));
if (module == null)
{
throw new Exception("there are no non-empty modules");
}
var unit = module.Units.Find(u => u.Sections.Count > 0);
var section = unit.Sections.First();
doSomeStuff(module, unit, section);
我最终编写了自己的函数来做到这一点:
private Tuple<Module, Unit, Section> getFirstModuleWithVisibleSection(List<Module> modules)
{
foreach (var module in modules)
{
foreach (var unit in module.Units)
{
var section = unit.Sections.FirstOrDefault();
if (section != null)
{
return new Tuple<Module, Unit, Section>(module, unit, section);
}
}
}
return null;
}
...
var res = getFirstModuleWithVisibleSection(modules);
if (res == null)
{
throw new Exception("no visible modules");
}
var module = res.Item1;
var unit = res.Item2;
var section = res.Item3;
doSomething(module, unit, section);
这很有效,但是比我希望的要冗长得多。
我更习惯OCaml,在这里我会使用List.find_map
,就像find
一样,除了返回null或not-null而不是返回true / false之外,它返回第一个不为零。在C#中看起来像这样:
var (module, unit, section) =
modules.FindMap(module =>
module.Units.FindMap(unit =>
{
var section = unit.Sections.FirstOrDefault();
if (section == null)
{
return null;
}
return (module, unit, section);
}));
在C#中有没有办法做到这一点?
答案 0 :(得分:4)
那又怎么样:
var query = from m in modules
from u in m.Units
let s = u.Sections.FirstOrDefault()
where s != null
select new
{
m,
u,
s
};
var item = query.FirstOrDefault();
答案 1 :(得分:1)
肯定不是很优雅,但可以满足需要。
public Module FirstModuleWithAUnitWithASection(IEnumerable<Module> modules)
=> modules.Where(module => module.Units != null)
.Select(module => module.Units.Where(unit => unit.Sections != null)
.Select(unit => unit.Sections.Select(section => module)
.First()).First()).First();