我有一个Option<T>
实例的集合,想从IEnumerable<Option<T>>
转换为Option<IEnumerable<T>>
如果 ALL 选项中有一个值,那么我想要一个Some<IEnumerable<T>>
并带有收集的值,如果集合中 ANY 个项目是{{ 1}},然后我要一个None
这似乎是一个相当普通的功能转换,但是我不确定它是否存在于主流功能库中,或者被称为什么。似乎与None<IEnumerable<T>>
类似,但不完全相同,因为我不想只滤除FlatMap
的值。
我可以自己实现它,但想了解它是否已经作为功能构造存在。不用介意使用什么语言,C#,Scala,Haskell等。
答案 0 :(得分:2)
这些语言结构最初不是用C#表示的。但是,为此目的有多个功能编程库。我的选择是Paul Louth的language-ext;到目前为止,我为C#找到的最丰富的FP库。
答案 1 :(得分:2)
功能编程概念有多个“语言族”。
在Haskell(显然是Scala)中,这称为connect.Method = "connect";
connect.Data = new Dictionary<string, object>();
connect.Data.Add("data", new Dictionary<string, object>()
{
{ "somekey", "data" },
{ "somekey2", "data" },
{ "somekey3", "data" },
{ "somekey4", "data" }
}
);
,是称为Traversable的抽象或类型类的一部分; sequence
是遍历的一种特殊情况。
存在其他语言家族,最著名的是ML。这就是术语sequence
的来源(在Haskell中称为Option
)。虽然我精通F#(这是一种ML方言),但我不知道遍历/顺序在这里已经建立了专门的术语。
答案 2 :(得分:1)
正如您说的那样,您不介意该语言,我在这里有一个使用F#的示例,该示例开箱即用Namespace.GetAddressEntryFromID
:
Option<T>
如果您不熟悉F#,let chooseAll source =
let anyNone = source |> Seq.exists Option.isNone
if anyNone then None else Some source
let s = [Some 1; Some 2; None]
let result1 = s |> chooseAll // None
let s = [Some 4; Some 5]
let result2 = s |> chooseAll // Some {4;5}
是Seq
的类型别名。这里的IEnumerable<T>
具有签名chooseAll
,其翻译为C#友好语法为seq<'a option> -> seq<'a> option
。
答案 3 :(得分:0)
您可以滚动自己的扩展方法,该方法依赖于System.Linq命名空间中的可用原语:
public static Option<IEnumerable<T>> AllSome<T>(this IEnumerable<Option<T>> input)
where T : class
=> (input.All(o => o.IsSome)) ?
new Some<IEnumerable<T>>(input.Select(o => (o as Some<T>).Value)) :
new None<IEnumerable<T>>() as Option<IEnumerable<T>>;
这是基于我为支持该示例而编写的Option类型的一次性实现的,可以根据您的Option风格随意调整:
public class Option<T>
where T: class
{
protected T value;
public bool IsSome => value != default(T);
}
public class Some<T> : Option<T>
where T: class
{
public Some(T value) => base.value = value;
public T Value => base.value;
}
public class None<T> : Option<T>
where T: class
{
}
答案 4 :(得分:0)
我玩了一点,在这种情况下似乎可以使用f#fold和foldBack。以下是一些示例:
let l1 = [Some 1; Some 2; None]
let l2 = [Some 3; Some 4; Some 5]
let acc (ac: int list option) le =
match ac, le with
| Some ac, Some le -> Some (le::ac)
| _, _ -> None
//this will reverse the order of elements if all present
let r1 = l1 |> List.fold acc (Some [])
let r2 = l2 |> List.fold acc (Some [])
//the order of elements preserved
let acc2 le (ac: int list option) = acc ac le
let r3 = List.foldBack acc2 l1 (Some [])
let r4 = List.foldBack acc2 l2 (Some [])
//or...
let r3b = l1 |> List.foldBack acc2 <| (Some [])
let r4b = l2 |> List.foldBack acc2 <| (Some [])
答案 5 :(得分:0)
此处是语言扩展作者,您只需调用.Sequence()
即可反转内部和外部单子信号。
IEnumerable<Option<int>> items = ...;
Option<IEnumerable<int>> result = items.Sequence();
如果序列中的任何一项为None
,则返回None
,否则为Some
,它具有您要查找的返回.Traverse(...)
的确切行为。
您还可以随时使用ROW_NUMBER()
映射结果。