19

SelectMany 将遍历对象树:

class Agency { List<Employees> Staff }

IEnumerable<Agency> Agencies

IEnumerable<Employee> =  
from anAgency in Agencies  
from anEmployee in anAgency.Staff. 
select anEmployee; 

通常,我总是先选择一个机构,然后使用员工的内部实例来获取员工。但在政府关闭的情况下,我只想列出每个人,看看谁能覆盖。

在这种不适合我的对象模型的罕见情况下,我可以使用 SelectMany 任意遍历树。

你把这种遍历称为什么?交叉连接?这不是因为加入已经隐含在 Agency 对象中的 Staff 组合中。

是绑定的吗?我对绑定一无所知。

除了Select, Many没有别的名字吗?!

4

2 回答 2

50

SelectMany在 C# 中对应于 Haskell(>>=)flatMapScala 中的绑定。Haskell 中的签名>>=是:

(>>=) :: Monad m => m a -> (a -> m b) -> m b

所以 bind 是一种用于从另一个构造一个单值的操作。

在 C# 的情况下,m上面的签名是IEnumerable,IObservableIQueryable。对于IEnumerable,SelectMany

IEnumerable<A> -> (A -> IEnumerable<B>) -> IEnumerable<B>

或在 C# 中

public static IEnumerable<B> SelectMany<A, B>(this IEnumerable<A> first, Func<A, IEnumerable<B>> selector)

bind 的含义取决于 monad 类型,对于 IEnumerable,输入序列中的每个元素都用于创建一个新序列,将得到的序列序列展平以产生输出序列。

绑定的另一种表述可以使这一点更清楚。虽然 monad 通常根据它们的 bind 实现来描述,但 monad 还必须支持另外两个操作,mapjoin.

map对应于 C# 中的 Select ,如下所示:

map :: Monad m => (a -> b) -> (ma -> m b)

所以这是一种将常规函数提升到一元值之上的“结构保持”方式。

join有类型

join :: Monad m => m m a -> m a

所以 join 用于扁平化嵌套的一元值。在 C# 中,这看起来像

public static IEnumerable<A> Join<A>(this IEnumerable<IEnumerable<A>> nested)

bind可以根据 map 和 join as 来实现

m >>= f = join (map f m)

所以要回答原始问题,SelectMany对应bindflatMap用其他语言。Bind 不仅仅是展平,还可以看作是一种转换,然后是嵌套的单子值(例如 的情况下的序列IEnumerable<T>)的展平。joinforIEnumerable<T>在当前的 linq 扩展中不存在。

于 2013-11-23T20:36:03.267 回答
4

在 .NET 世界之外,它通常被称为“扁平化”,如果这就是您所要求的。它将二维结果集展平为一维。

于 2013-10-11T15:31:42.807 回答