【问题标题】:Selecting elements of a cell using a logical matrix使用逻辑矩阵选择单元格的元素
【发布时间】:2015-06-29 21:59:37
【问题描述】:

想象一下,我有一个像这样的空元胞数组:

dim = [100,200];

x = cell(dim);

我想用'a'(字符串)替换x的对角线元素。这就是我所做的:

mask = logical(eye(dim));
x{mask} = {'a'};

但是,我收到以下错误:

这个赋值的右边的值太少,无法满足 左侧

测试错误(第 28 行)

x{掩码} = {'a'};

我也试过了:

mask_2 = find(mask == true);
x{mask_2} = {'a'};

但我得到了同样的错误。有没有办法解决这个问题?我希望脚本尽可能高效。

【问题讨论】:

    标签: arrays matlab cell-array


    【解决方案1】:

    我知道有两种方法可以做到这一点。

    第一种是用括号代替括号寻址。这将为每个地址返回一个元胞数组引用,因此您必须为结果分配一个元胞数组:

    x(mask) = {'a'};
    

    第二种是使用括号寻址,它将返回一个逗号分隔的列表。那是什么?您从未听说过 Matlab 中的comma-separated list?这是因为它是 Matlab 中最不为人所知的数据类型,尽管我向您保证您以前见过它。阅读链接以获取更多信息。我发现,一旦我了解了逗号分隔列表是什么以及它们的使用位置,Matlab 的许多“怪异之处”就会变得更有意义。

    无论如何,如果您尝试编写x{mask} = 'a',它将无法正常工作,因为您尝试将单个值分配给以逗号分隔的引用列表。您可以使用 deal 函数通过巧妙地连接引用来分配给每个引用:

    [x{mask}] = deal('a');
    

    你有它。使用逻辑索引分配给元胞数组的两种方法。不过我不确定哪个更快,你必须自己测试一下。

    【讨论】:

    • 非常好的答案。我认为不能将逗号分隔的列表严格视为一种数据类型。但是你是绝对正确的,一旦你了解了逗号分隔列表是什么以及它们的使用位置,Matlab 的许多“怪异”就会变得更有意义
    【解决方案2】:

    要引用一组单元格,请使用 Matlab 文档中所说的“圆括号”,或者我们所说的普通括号:

    http://www.mathworks.com/help/matlab/matlab_prog/access-data-in-a-cell-array.html

    x(mask) = {'a'}
    

    dim = [5,6] 的结果:

    x =
    {
      [1,1] = a
      [2,1] = [](0x0)
      [3,1] = [](0x0)
      [4,1] = [](0x0)
      [5,1] = [](0x0)
      [1,2] = [](0x0)
      [2,2] = a
      [3,2] = [](0x0)
      [4,2] = [](0x0)
      [5,2] = [](0x0)
      [1,3] = [](0x0)
      [2,3] = [](0x0)
      [3,3] = a
      [4,3] = [](0x0)
      [5,3] = [](0x0)
      [1,4] = [](0x0)
      [2,4] = [](0x0)
      [3,4] = [](0x0)
      [4,4] = a
      [5,4] = [](0x0)
      [1,5] = [](0x0)
      [2,5] = [](0x0)
      [3,5] = [](0x0)
      [4,5] = [](0x0)
      [5,5] = a
      [1,6] = [](0x0)
      [2,6] = [](0x0)
      [3,6] = [](0x0)
      [4,6] = [](0x0)
      [5,6] = [](0x0)
    }
    

    【讨论】:

    • 我创建了一个 MATLAB 聊天室,供我们讨论与 MATLAB 相关的事情,或者进行超出单个评论限制的讨论。有时间就来找我们吧! - chat.*.com/rooms/81987/matlab
    【解决方案3】:

    除了此处给出的解释之外,您还可以避免创建(可能很大)逻辑数组,如果这是其唯一目的,并使用linear indexing 直接使用sub2ind 函数分配值:

    dim = [100,200];
    x = cell(dim);
    x(sub2ind(dim,1:dim(1),1:dim(1))) = {'a'};
    

    正如 cmets 中提到的,sub2ind 函数在这里很容易回避,因为对角线元素之间的步幅是一个常数值(行数)。所以上面可以简化为

    x(1:dim(1)+1:dim(1)^2) = {'a'};
    

    【讨论】:

    • 或者,x(1:dim(1)+1:dim(1)*dim(2)) = {'a'}
    • 在这种情况下很容易回避sub2ind: x(1:size(x)+1:end) = {'a'}
    • @beaker 说得好:-D
    • @LuisMendo 我更喜欢你的。 ;-)
    • @beaker 此处确实不需要该功能。我想我有偏见,因为我一直使用它来更新非对称矩阵。 ^^"
    【解决方案4】:

    另一个选项(一个班轮,我最喜欢的解决方案),使用问题中提出的逻辑(eye 函数等):

    x=num2cell(char(eye(n,m)*97),n)
    

    其中dim=[n,m]97 将编码字符串'a'...

    【讨论】: