我喜欢在Option []的F#中使用Array.choose id。在C#中为Nullable []执行此操作的最佳方法是什么?
---编辑以解决出色的评论---
在F#中,我使用Array.choose id
过滤掉None
:Option<'T>[] -> 'T []
。
使用Linq null
在C#中过滤掉Nullable<T>[] => T []
的好方法是什么?
答案 0 :(得分:3)
我会用C#将其翻译成这个
int?[] all = new int?[3] { 10, null, 100 };
int[] chosen = all
.Where(e => e.HasValue)
.Select(e => e.Value)
.ToArray();
如果只希望将其作为IEnumerable,则可以省略ToArray()
,如果不希望将nullable拆开,则可以省略.Select(..)
答案 1 :(得分:1)
您可以使用SelectMany
给定的另一个函数将T?
转换为IEnumerable<T>
:
public static IEnumerable<T> ToSeq<T>(this T? v) where T : struct
{
if (v.HasValue)
{
yield return v.Value;
}
}
然后:
var nullables = new int?[] { null, 1, 4, null, 3, null, 29 };
int[] values = nullables.SelectMany(ni => ni.ToSeq()).ToArray();
答案 2 :(得分:0)
如果您是F#Option的粉丝,您可能会喜欢C#中的Optional库。
无论如何,我喜欢为此使用扩展方法。我将其与该Optional库一起使用,但这是一个Nullable版本。此版本仅限于输出值类型,但Option版本也可以处理引用类型。
/// <summary>
/// Allows you to map and filter in a single operation, by passing in a function that returns
/// a Nullable containing the output that should be included in the final result.
/// Only the values that are not null are included in the resulting sequence.
/// </summary>
public static IEnumerable<T2> Choose<T1, T2>(this IEnumerable<T1> enumerable, Func<T1, T2?> selector) where T2 : struct
{
if (enumerable is null) throw new ArgumentNullException(nameof(enumerable));
if (selector is null) throw new ArgumentNullException(nameof(selector));
// The nested function ensures argument validation happens immediately, rather than
// being delayed until the caller starts iterating the results.
IEnumerable<T2> iterator()
{
foreach (var item in enumerable)
{
var output = selector(item);
if (output.HasValue)
yield return output.Value;
}
}
return iterator();
}