将 ismember 扩展到单元格

Extending ismember to cells

我搜索了论坛,但没有找到足够的信息来帮助我解决这个问题。

考虑集合(向量元胞)

A = {[1],[1 2],[2],[1 2 3],[1 2 3 4],[1 3]}

我想构造一个矩阵 B 看起来像

B = [1 1 0 1 1 1
     0 1 0 1 1 0
     0 1 1 1 1 0
     0 0 0 1 1 0
     0 0 0 0 1 0
     0 0 0 1 1 1]

矩阵 B 指定向量相对于彼此的从属关系。也就是说,第一行查看 A 中的第一个元素 [1],并检查它是否是其他向量的成员,如果是成员则放置 1,否则放置 0。

我可以使用两个 for 循环来做到这一点:一个遍历 A 的元素,另一个嵌套,用于 A 的每个元素,检查相对于 A 的每个其他成员的成员资格。

我想避免使用 for 循环。有没有从A得到B的矢量化方案?

对于元胞数组,很难避免循环,或者它们的表亲 cellfun。我会这样做:

[ii, jj] = ndgrid(1:numel(A)); % indices of all possible pairs
result = cellfun(@(x,y) all(ismember(x,y)), A(ii), A(jj)); % see if all elements in the 
    % first are present in the second

好吧,这是您自找的,所以这里有一个几乎*矢量化的解决方案,使用 bsxfun and permute -

lens = cellfun('length',A) 
vals = [A{:}]

mask = bsxfun(@ge,lens,[1:max(vals)]')
a = nan(size(mask))
a(mask) = vals
matches =  bsxfun(@eq,a,permute(a,[3,4,1,2]));
out = bsxfun(@eq,squeeze(sum(any(matches,3),1)),lens(:))

*: 几乎是因为在 cellfun('length',A) 开始时使用了 cellfun,但由于它只是获取那里的单元格的长度,因此在计算上可以忽略不计。

另请注意,此方法会占用大量内存资源,因此可能没有任何好处,但尽可能尊重矢量化解决方案的要求!