【问题标题】:Iterate over diagonal elements of a Matrix in MatLab在 MatLab 中迭代矩阵的对角线元素
【发布时间】:2016-09-04 10:11:34
【问题描述】:

我需要获取矩阵中所有对角线的索引。矩阵可以是非正方形的。

diag 函数给出了值,但我需要坐标。因此,例如:[1 2 3; 4 5 6; 7 8 9],我想要[1 1; 2 2; 3;3] 加上[2 6] 和3,因为它们是矩阵的上对角线,下面相同,即[4 8] 和7。所以完整的索引列表是:[1 1; 2 2; 3 3], [1 2; 2 3], [1 3], [2 1], [3 2], [3 1]。

而且我在另一个对角线方向也需要这个......

它需要适用于任何形状的矩阵,即不仅仅是方形矩阵,包括向量(即 1xn 和 nx1) - 但我想我可以测试最后两种情况并分别处理。

编辑: 一个非方阵的例子是这个 3x2 的:

1   2
3   4
5   6

在这种情况下,我需要的索引是:

[1 1; 2 2]
[2 1; 3 2]
[1 2]
[3 1]

然后对角线以另一种方式运行......

我知道diag 函数并且可以编写一些代码来迭代矩阵,但是我不知道如何轻松地将这些值转换为索引。

至于我为什么需要这个:这是我在 MatLab 中做的一门在线课程。编程介绍,使用 MatLab。我是一名经验丰富的程序员,但我对 MatLab 不熟悉,我想进一步了解它。

这个问题要求我们在任何方向上找到任何n 数字的最大乘积,即行、列和对角线(双向)。问题是我们不返回产品,我们返回构成该产品的元素的索引。

我希望这能提供更多信息。

编辑 2: 很抱歉没有回复你们,我一直忙于做其他事情。当我第一次在这里发帖时,我以为我遗漏了一些东西,而这需要几行。但这比这更棘手,所以你们发布的代码将花费我更多的时间来阅读和理解等。但我希望今天做到这一点并接受一个作为答案。谢谢大家的回复。

【问题讨论】:

  • 输出的形状应该是什么?你的alt_diag 是否也得到对角线的位置(-2,-1,0,1,2)?你能提供一个非方阵的例子(输入和输出)吗?
  • 你打算如何处理这些索引?您需要索引本身,还是需要获取值并对它们执行一些操作?如果是后者,您可以使用diag 检索任何对角线的值,即使是在非方阵上。
  • 好的,所以输出的形状需要是这些索引的列表。所以对于上面的2x2矩阵,索引其实是:[1 1; 2 2; 3 3], [1 2; 2 3]、[1 3]、[2 1]、[3 2]、[3 1]。我已经更新了上面的问题。
  • 由于是家庭作业,我不会提供完整的答案,但您应该能够定义对角线M(i,i),然后使用线性索引来移动它们。然后手动(这很容易)转换为 (i,j) 索引或使用sub2ind。如果您使用线性索引,这应该很简单。将对角线向右移动与idxArray = idxArray+size(M,1) 相同。向下移动对角线只会是idxArray=idxArray+1。请记住对角线可能会变短...
  • @davo36 关于您的编辑,不用担心。慢慢来,了解问题和解决方案,如果您有任何问题,请与我们联系。

标签: matlab matrix octave diagonal


【解决方案1】:

不要忘记,Matlab 理解对多维矩阵的线性索引。对于 OP 的 3*3(我们称之为 a)矩阵的示例,表达式 a(3) 标识与 a(3,1) 相同的元素(Matlab 使用列优先布局)。因此,对于k*k 矩阵,表达式

[1, k+2, 2k+3, 3k+4, ...]

给出主对角线上元素的索引。有多种方法可以生成该向量。然后,明智地应用ind2sub 会将二维索引赋予相同的矩阵。

将这种方法推广到其他对角线和非方阵应该不难。

【讨论】:

    【解决方案2】:

    这是“从西北到东南”对角线的解决方案。

    A = [1,2,3,4,5;6,7,8,9,10;11,12,13,14,15];  
    rows = size (A,1);   cols = size (A,2);   padding = rows - 1; 
    padded = [ones(rows, padding), A, ones(rows, padding)];
    
    % Create a Helper array containing column/row pairs and a product
    Helper = zeros (cols + padding, rows * 2 + 1);
    for i = 1 : cols + padding;  % i moves along columns of the padded array
      i0 = i - padding; % "actual" index w.r.t A, where leftmost index is 1-padding
      c  = 1;       % a counter used for filling current "Helper" row appropriately
      for j = 1 : rows;       % j moves along rows
        Helper(i, c)   = i0;  % store current "actual" column
        Helper(i, c+1) = j;   % store current row
        c  = c  + 2;          % move to next 2 slots in "Helper"
        i0 = i0 + 1;          % move to next "actual" column for processing
      end 
    
      % Process product at appropriate indices
      Helper(i, end) = prod (padded (sub2ind (       ...
                         size (padded),              ...
                         Helper(i,2:2:end-1),        ...
                         Helper(i,1:2:end-1)+padding ...
                       )));
    end
    
    % Isolate the correct indices for which the product is largest
    [~, biggest] = max (Helper(:, end)); % column index of largest product in Helper
    Pairs = reshape (Helper(biggest, 1:end-1), 2, []); % collect indices
    Pairs = fliplr (Pairs.');                          % express as rows/cols
    
    % Remove pairs where column occurs in the "padded" zone
    for i = 1 : size (Pairs, 1)
      if Pairs(i, 1) < 1 || Pairs(i, 1) > cols; Pairs(i, :) = []; end
    end
    
    display(Pairs)
    

    如果您了解这背后的逻辑,那么“从东北到西南”的对角线也应该是小菜一碟。我会留给你弄清楚:)

    【讨论】:

    • 嗨,非常感谢您发布答案,但我无法让它运行。我明白了:“double”类型的输入参数的未定义函数“padarray”。 diagTest 错误(第 3 行) padded = padarray (A, [0, padding], 1, 'both');我复制了您的代码并将其放入 .m 文件中,然后通过输入该文件的名称来运行它。这是执行它的正确方法吗?
    • 啊,padarray 是Image Processing Toolbox 的一部分,看来您只有基本的matlab。不用担心,它所做的只是在每一边添加一堆“零”或“一”。我已经编辑了代码以手动执行此操作。这是一个脚本,因此您可以将其作为文件运行,也可以只复制终端上的所有内容,是的。 (即它不是一个函数!您的“输入”矩阵只是定义为脚本中的第一行)
    【解决方案3】:

    执行此操作的简单方法是构造一个与输入形状相同的数组,其中每个元素的值是它的索引。然后你可以得到每个对角线的值(索引)。

    function diag_cell = alldiags(A)    
       [m,n] = size(A);
    
       M = reshape(1:m*n, m, n);   % construct array of indices
       % there are (m-1) diagonals below the main (k parameter negative)
       %   and (n-1) diagonals above, plus 0 for the main diagonal
       for d = 1-m:n-1
          C1{d+m} = diag(M, d);   % store in C1{1}..C1{m+n-1}
       end
    
       % to get the antidiagonals, rotate the index matrix `M` and repeat
       %   (remember to swap `m` and `n`):
       M = rot90(M);
       for d = 1-n:m-1
          C2{d+n} = diag(M, d);
       end
    
       diag_cell = {C1{:}, C2{:}};   % concatenate the cell arrays and return
    end
    

    这是一个使用 3x3 样本矩阵的测试运行:

    A =
    
       1   2   3
       4   5   6
       7   8   9
    
    >> alldiags(A)
    ans =
    {
      [1,1] =  3
      [1,2] =
    
         2
         6
    
      [1,3] =
    
         1
         5
         9
    
      [1,4] =
    
         4
         8
    
      [1,5] =  7
      [1,6] =  1
      [1,7] =
    
         4
         2
    
      [1,8] =
    
         7
         5
         3
    
      [1,9] =
    
         8
         6
    
      [1,10] =  9
    }
    

    如果确实需要,您可以随时将所有索引转换为下标,但如果您要访问原始矩阵,使用索引可能更容易。这是一个将主对角线转换为下标的示例:

    >> C{3}
    ans =
    
       1
       5
       9
    
    >> [r,c] = ind2sub(size(A), C{3});
    >> subs = [r c]
    subs =
    
       1   1
       2   2
       3   3
    

    这里有一个例子来说明为什么这样做。让我们取一个随机的 6x3 矩阵A:

    A =
    
       0.634825   0.560609   0.926716
       0.049504   0.226152   0.748278
       0.746754   0.493896   0.773868
       0.993245   0.457522   0.412092
       0.430003   0.695042   0.641917
       0.935298   0.960166   0.022872
    

    函数做的第一件事是获取输入矩阵A 的大小并创建一个相同大小的新矩阵,使每个元素的值等于其线性索引。线性索引从1 到下标[1,1] 开始,在列向下增加到m 在[m,1],然后转到m+1 下标[1,2],在索引m*n 下标[m,n] 结束。

    >> [m,n] = size(A)
    m =  6
    n =  3
    >> M = reshape(1:m*n, m, n)
    M =
    
        1    7   13
        2    8   14
        3    9   15
        4   10   16
        5   11   17
        6   12   18
    

    此矩阵的输出diag_cell 如下所示(经过大量重新格式化,以便一次查看所有内容):

    diag_cell =
    {
      [1,1]  =   6
      [1,2]  =   5    12
      [1,3]  =   4    11    18
      [1,4]  =   3    10    17
      [1,5]  =   2     9    16
      [1,6]  =   1     8    15
      [1,7]  =   7    14
      [1,8]  =  13
      [1,9]  =   1
      [1,10] =   7     2
      [1,11] =  13     8     3
      [1,12] =  14     9     4
      [1,13] =  15    10     5
      [1,14] =  16    11     6
      [1,15] =  17    12
      [1,16] =  18
    }
    

    前半部分是正常的对角线(从左上到右下),后半部分是对角线(从右上到左下)。

    以对角线diag_cell{4} = [3; 10; 17] 为例。您可以查看矩阵 M 以查看这些索引所指的元素。

    A =
    
       0.634825   0.560609   0.926716
       0.049504   0.226152   0.748278
      *0.746754*  0.493896   0.773868
       0.993245  *0.457522*  0.412092
       0.430003   0.695042  *0.641917*
       0.935298   0.960166   0.022872
    

    这条对角线从[3,1] 开始,到[5,3] 结束。如果我们从A 中恢复值,我们会得到:

    >> A(diag_cell{4})
    ans =
    
       0.74675
       0.45752
       0.64192
    

    【讨论】:

    • 嗯,谢谢你,但我不太明白。你已经得到了所有的对角线值,但就我所见,还没有得到这些对角线的索引?告诉我我是否错了?因此,例如,对于那个主对角线 1,5,9,我想要它的索引,即 [1,1; 2,2; 3,3]。对于 4,8 的较小对角线,我想要 [2 1; 3 2]
    • 不,这就是我构建新矩阵的原因。新矩阵的每个条目都等于它的索引。当您获得对角线的值时,您将获得对角线的索引。你所说的索引,[1, 1; 2, 2; 3, 3] 是我上面提到的下标。如果需要,您可以使用 ind2sub 恢复它们,但这取决于您以后对它们做什么。
    • 参见stackoverflow.com/questions/32379805/… 了解 MATLAB 中的线性索引。
    • 我添加了一个转换为下标的示例。当然,如果您需要,可以将其添加到函数本身。
    • 好的,谢谢,这对非方阵有用吗?好像没有?
    【解决方案4】:

    此解决方案一直到您的最终任务 - 找到矩阵中任何向量的最大乘积的索引:

    function out = maxVecProd(A)
    % validate the input is a vector\matrix:
    assert(ismatrix(A),'Input must be a vector or matrix')
    [cmax,cind] = max(prod(A,1)); % find where the maximum prod in the columns
    [rmax,rind] = max(prod(A,2)); % find where the maximum prod in the rows
    if all(size(A))>1 % if its a matrix:
        all_d = -(size(A,1)-1):(size(A,1)-1); % get all the valid diagonals
        pd = zeros(2*numel(all_d),2); % the solution of all products
        c = 1;
        for d = all_d
            pd(c,1) = prod(diag(A,d)); % get the diagonal product
            pd(c,2) = prod(diag(fliplr(A),d)); % get the anti-diagonal product
            c = c+1;
        end
        [dmax,dind] = max(pd(:)); % find where the maximum prod in the diagonals
        % get the orientation of the maximum prod (column, row, diagonal)
        [~,dirmax] = max([rmax,cmax,dmax]);
    else
        [~,dirmax] = max([rmax,cmax]);
    end
    switch dirmax
        case 1
            % create the indices for the maximum row:
            out = [repelem(rind,size(A,2)).' (1:size(A,2)).'];
        case 2
            % create the indices for the maximum column:
            out = [(1:size(A,1)).' repelem(cind,size(A,1)).'];
        case 3
            [r,dir] = ind2sub(size(pd),dind); % convert to [row,column]
            d_ind = all_d(r); % find which value of d gave the maximum product
            [R,C] = ndgrid(1:size(A,1),1:size(A,2)); % create a grid of all indices
            if dir==1
                % find the indices for a diagonal:
                out = [diag(R,d_ind),diag(C,d_ind)];
            else
                % find the indices for an anti-diagonal:
                out = [diag(fliplr(R),d_ind),diag(fliplr(C),d_ind)];
            end
    end
    end
    

    你得到maxVecProd(A):

    out =
         1     2
         2     2
         3     2
    

    这意味着最大的 prod 是 (1,2)、(2,2) 和 (3,2) 中的元素。

    【讨论】:

    • 请问在这个例子中你对 n 有什么价值?在问题中,n 是指要相乘的元素的数量。例如,它可能是一个 4x6 矩阵,但任何行、列或对角线上的 3 个数字相乘在一起形成一个乘积。因此,沿每行、每列或对角线滑动 3 个窗口。
    • 我想我应该在一开始就这么说,但这就是为什么我一直要求下标(或索引或​​其他)。这样我就可以进行最后的计算了.... gah.
    • 嗨,这很接近,但它不适用于一维向量,我明白了:Assignment has more non-singleton rhs dimension than non-singleton subscripts DiagTest2 中的错误(第 12 行) pd(c ,1) = 产品(诊断(A,d)); % 得到对角积
    • 对,我已经编辑了包含该案例的答案。我还添加了一个检查 A 不是未定义对角线的 ND 数组(超过 2D),并扭曲了函数中的所有内容。随意询问任何不清楚的部分;)
    【解决方案5】:

    好的,所以我昨晚自己编写了这个代码。它很长,我相信它可以以更好的方式完成。我不太了解 MatLab,所以我的解决方案非常幼稚。但它有效。

    function indicies = maxproduct(A, n)
    
    
    function diagIndicies = getAllReverseDiagonalIndicies()
        % This function returns lists of indicies in the reverse diagonal direction (top-right to bottom-left)
        if rows == 1 
            numCells = 0;
            for j=1:length(A)
                temp = [1, j];
                numCells = numCells + 1;
                diagIndicies{numCells} = temp;
            end
            return
        end
    
        % This loop adds all diagonals down and to the right, to the end of the matrix.
        %fprintf('Diagonals down to main one are:\n');
        numCells = 0;
        for x=1:rows
            rowNum = x;
            colNum = 1;
            temp = [];
            while rowNum >= 1 && rowNum <= rows && colNum <= cols
                temp = [temp; [rowNum colNum]];
                rowNum = rowNum - 1;
                colNum = colNum + 1;
            end
            numCells = numCells + 1;
            temp = flipud(temp); % Need row major order for assignment
            %disp(temp);
            diagIndicies{numCells} = temp;
        end
    
        % Now go along bottom row
        %fprintf('Diagonals along bottom are:\n');
        for y=2:cols
            rowNum = rows;
            colNum = y;
            temp = [];
            while rowNum >= 1 && colNum <= cols
                temp = [temp; [rowNum colNum]];
                rowNum = rowNum - 1;
                colNum = colNum + 1;
            end
            numCells = numCells + 1;
            temp = flipud(temp); % Need row major order for assignment
            %disp(temp);
            diagIndicies{numCells} = temp;
        end                
    
    end
    
    function diagIndicies = getAllDiagonalIndicies()
        % This function returns lists of indicies in the main diagonal direction (top-left to bottom-right)
        if rows == 1 
            numCells = 0;
            for j=1:length(A)
                temp = [1, j];
                numCells = numCells + 1;
                diagIndicies{numCells} = temp;
            end
            return
        end
    
         % This loop adds all diagonals down and to the left, to the lhs of the matrix.
        %fprintf('Diagonals down to main one are:\n');
        numCells = 0;
        for x=1:rows
            rowNum = x;
            colNum = cols;
            temp = [];
            while rowNum >= 1 && rowNum <= rows && colNum >= 1
                temp = [temp; [rowNum colNum]];
                rowNum = rowNum - 1;
                colNum = colNum - 1;
            end
            numCells = numCells + 1;
            temp = flipud(temp); % Need row major order for assignment
            %disp(temp);
            diagIndicies{numCells} = temp;
        end
    
        % Now go along bottom row...
        %fprintf('Diagonals along bottom are:\n');
        for y=cols-1:-1:1
            rowNum = rows;
            colNum = y;
            temp = [];
            while rowNum >= 1 && colNum >= 1
                temp = [temp; [rowNum colNum]];
                rowNum = rowNum - 1;
                colNum = colNum - 1;
            end
            numCells = numCells + 1;
            temp = flipud(temp); % Need row major order for assignment
            %disp(temp);
            diagIndicies{numCells} = temp;
        end
    
     end
    
    
     % Main function starts here.
    
    [rows, cols] = size(A);
    
    theMaxProduct = -10000000;
    indicies = [];
    
    if isscalar(A)
        if A == 1 && n == 1
            indicies = [1,1];
            return;
        else
            return;
        end
    end
    
    
    
    % Find max product in each row of A
    for i=1:rows
        for j=1:cols-n+1
            theProduct = 1;
            for k=j:j+n-1
                theProduct = theProduct * A(i, k);
            end
            if theProduct > theMaxProduct
                theMaxProduct = theProduct;
                indicies = [];
                for k=j:j+n-1
                    indicies = [indicies; [i, k]];
                end
    
            end
        end
    end
    fprintf('theMaxProduct after examining rows = %15.15f\n', theMaxProduct);
    
    % Find max product in each column of A
    for i=1:cols
        for j=1:rows-n+1
            theProduct = 1;
            for k=j:j+n-1
                theProduct = theProduct * A(k, i);
            end
            if theProduct > theMaxProduct
                theMaxProduct = theProduct;
                indicies = [];
                for k=j:j+n-1
                    indicies = [indicies; [k, i]];
                end
    
            end
        end
    end
    fprintf('theMaxProduct after examining cols = %15.15f\n', theMaxProduct);
    
    
    
    % Find max product along reverse diagonals of A
    diagIndicies = getAllReverseDiagonalIndicies();
    %disp(diagIndicies);
    for i=1: length(diagIndicies)
        [numIndicies, ~] = size(diagIndicies{i});
        for j=1:numIndicies-n+1
            theProduct = 1;
            for k=j:j+n-1
                theProduct = theProduct * A(diagIndicies{i}(k, 1), diagIndicies{i}(k, 2));
            end
            if theProduct > theMaxProduct
                theMaxProduct = theProduct;
                indicies = [];
                for k=j:j+n-1
                    indicies = [indicies; [diagIndicies{i}(k, 1), diagIndicies{i}(k, 2)]];
                end
    
            end
        end
    end
    fprintf('theMaxProduct after examining reverse diag = %15.15f\n', theMaxProduct);
    
    
    % Find max product along diagonals of A
    diagIndicies = getAllDiagonalIndicies();
    %disp(diagIndicies);
    for i=1: length(diagIndicies)
        [numIndicies, ~] = size(diagIndicies{i});
        for j=1:numIndicies-n+1
            theProduct = 1;
            for k=j:j+n-1
                theProduct = theProduct * A(diagIndicies{i}(k, 1), diagIndicies{i}(k, 2));
            end
            if theProduct > theMaxProduct
                theMaxProduct = theProduct;
                indicies = [];
                for k=j:j+n-1
                    indicies = [indicies; [diagIndicies{i}(k, 1), diagIndicies{i}(k, 2)]];
                end
    
            end
        end
    end
    fprintf('theMaxProduct after examining main diag = %15.15f\n', theMaxProduct);
    

    结束

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-05
      • 1970-01-01
      相关资源
      最近更新 更多