gpt4 book ai didi

c# - 产量返回 brainfreeze

转载 作者:行者123 更新时间:2023-11-30 13:32:16 24 4
gpt4 key购买 nike

假设我有这样的方法:

IEnumerable<record> GetSomeRecords()
{
while(...)
{
yield return aRecord
}
}

现在,假设我有一个调用者,它也返回一个相同类型的可枚举,就像这样

IEnumerable<record> ParentGetSomeRecords()
{
// I want to do this, but for some reason, my brain locks right here
foreach(item in someItems)
yield return GetSomeRecords();
}

该代码出现语法错误错误,因为 yield return 需要一个类型记录,而我正在返回一个 IEnumerable 记录

我想要一个“扁平化”IEnumerable,它可以扁平化可枚举的嵌套循环。这让我发疯,因为我知道我以前做过,但我似乎不记得那是什么。有什么提示吗?

最佳答案

这就是你想要的吗?

IEnumerable<record> ParentGetSomeRecords()
{
foreach(var item in someItems)
foreach(var record in GetSomeRecords())
yield return record;
}

如前所述,这仅适用于单个级别的 child ,但与您的示例代码最等效。

更新

有些人似乎认为您想要扁平化层次结构的能力。这是一个扩展方法,它执行广度优先展平(在 child 之前获得 sibling ):

来自单个项目:

[Pure]
public static IEnumerable<T> BreadthFirstFlatten<T>(this T source, Func<T, IEnumerable<T>> selector)
{
Contract.Requires(!ReferenceEquals(source, null));
Contract.Requires(selector != null);
Contract.Ensures(Contract.Result<IEnumerable<T>>() != null);

var pendingChildren = new List<T> {source};

while (pendingChildren.Any())
{
var localPending = pendingChildren.ToList();
pendingChildren.Clear();
foreach (var child in localPending)
{
yield return child;
var results = selector(child);
if (results != null)
pendingChildren.AddRange(results);
}
}
}

可以这样使用:

record rec = ...;
IEnumerable<record> flattened = rec.BreadthFirstFlatten(r => r.ChildRecords);

这将导致 IEnumerable<record>包含 rec ,所有 rec 的 child ,所有 child 的 child ,等等。

如果您来自 records 的集合,使用以下代码:

[Pure]
private static IEnumerable<T> BreadthFirstFlatten<T, TResult>(IEnumerable<T> source, Func<T, TResult> selector, Action<ICollection<T>, TResult> addMethod)
{
Contract.Requires(source != null);
Contract.Requires(selector != null);
Contract.Requires(addMethod != null);
Contract.Ensures(Contract.Result<IEnumerable<T>>() != null);

var pendingChildren = new List<T>(source);

while (pendingChildren.Any())
{
var localPending = pendingChildren.ToList();
pendingChildren.Clear();
foreach (var child in localPending)
{
yield return child;
var results = selector(child);
if (!ReferenceEquals(results, null))
addMethod(pendingChildren, results);
}
}
}

[Pure]
public static IEnumerable<T> BreadthFirstFlatten<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> selector)
{
Contract.Requires(source != null);
Contract.Requires(selector != null);
Contract.Ensures(Contract.Result<IEnumerable<T>>() != null);

return BreadthFirstFlatten(source, selector, (collection, arg2) => collection.AddRange(arg2));
}

[Pure]
public static IEnumerable<T> BreadthFirstFlatten<T>(this IEnumerable<T> source, Func<T, T> selector)
{
Contract.Requires(source != null);
Contract.Requires(selector != null);
Contract.Ensures(Contract.Result<IEnumerable<T>>() != null);

return BreadthFirstFlatten(source, selector, (collection, arg2) => collection.Add(arg2));
}

这两个扩展方法可以这样使用:

IEnumerable<records> records = ...;
IEnumerable<record> flattened = records.BreadthFirstFlatten(r => r.ChildRecords);

或者从相反的方向:

IEnumerable<record> records = ...;
IEnumerable<record> flattened = records.BreadthFirstFlatten(r => r.ParentRecords);

所有这些扩展方法都是迭代的,因此不受堆栈大小的限制。

我有一大堆这些类型的方法,包括前序和后序深度优先遍历,如果你想看它们,我会做一个 repo 并上传到某个地方:)

关于c# - 产量返回 brainfreeze,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15146366/

24 4 0
文章推荐: c# - 错误 No overload for 'timer_Tick' matches delegate 'System.EventHandler'