Get All Diagonal Vectors from Matrix

Get all diagonal vectors from matrix


A <- matrix(1:16, 4)

# create an indicator for all diagonals in the matrix
d <- row(A) - col(A)

# use split to group on these values
split(A, d)

#
# $`-3`
# [1] 13
#
# $`-2`
# [1] 9 14
#
# $`-1`
# [1] 5 10 15
#
# $`0`
# [1] 1 6 11 16
#
# $`1`
# [1] 2 7 12
#
# $`2`
# [1] 3 8
#
# $`3`
# [1] 4

How to print all the diagonal elements of a 2d vector

The solution is rather straigt forward. I will first show the code and then explain it.

#include <iostream>
#include <vector>

using Matrix = std::vector<std::vector<int>>;

int main() {

Matrix matrix{
{1,2,3,4},
{5,1,2,3},
{9,5,1,2}
};
// Shortcut for the width and height of the matrix
const size_t width{ matrix.at(0).size() };
const size_t height{ matrix.size() };

// Set start row and start column
size_t startRow{ height-1 };
size_t startColumn{ 0 };
size_t column{};

// for all possible start positions
do {
// set the row and column values to the start values
size_t row{ startRow };
column = startColumn;

//Now go through the diagonal
do {
// Show current value
std::cout << matrix[row][column] << ' ';

// Set next position in the diagonal
++row; // Go one row down
++column; // Go one column to the right

// As long as we do not cross the border
} while ((row < height) && (column < width));

std::cout << '\n';

// Calculate new start row and start column
// If possible
if (startRow > 0) {
// Go up
--startRow;
}
else {
// Else go right
++startColumn;
}
} while (startColumn < width);

return 0;
}

So, we need to play a little bit with indices.

The indices for a diagonal are very simple. Simply start at a startPosition,then we increment the row and the column in each step, until we hit the border.

For the start positions of the diagonal, we will start at the low left border. Then we will keep the column and decrement the row. If the row is 0 then we go to the right, until we hit the border.

All this can be formulated very easily in C++.

Extract elements from matrix diagonal saved in multiple lists in R


sapply(res, diag)

[,1] [,2]
[1,] 0.04770856 0.05436957
[2,] 0.03260190 0.10484454

# or
lapply(res, diag)
[[1]]
[1] 0.04770856 0.03260190

[[2]]
[1] 0.05436957 0.10484454

If you want the vectors for some reason in your global environment:

alld <- lapply(res, diag)
names(alld) <- sprintf("d.%d.el", 1:length(alld))
list2env(alld, globalenv())

Extracting off-diagonal elements of a matrix in R

If we need the off-diagonal, create a function where the row index is not equal to column index

odiag <- function(x) x[col(x) != row(x)]
odiag(mat_rix)

If we need the values that are one up/one down from the diagonal

odiag2 <- function(x, offdiag = "up") {
ind <- if(offdiag == "up") -1 else 1
x[row(x) - col(x) == ind]
}
odiag2(mat_rix, "up")
[1] 0 0 0 0 0 0 0 0 0 0

Get Diagonals in a Matrix

Some thoughts:

  1. You don't need a list of all the diagonals, what you need is the two diagonals for each queen in the board
  2. If you really, really want all the diagonals then it's better to change the data structure. Although I'm certain that this problem can be solved using lists, I'd rather switch to vectors so I can use indexes efficiently

Granted, anyway you can write a solution referencing indexes on a list via list-ref but it wouldn't be efficient/elegant. Or you could transform the lists into vectors with list->vector, write an index-based solution with vector-ref and then go back to lists with vector->list

For instance, you can try the following solution (adapted from this post). It receives a vector of vectors as input (if you want to use a list of lists as input simply replace vector-ref with list-ref, it'll be less efficient though), and returns a list of lists with the diagonals. The elements get added in a different order, but the values are correct (exercise for the reader: format the output so it matches the sample in the question). Notice how I'm using iterations and comprehensions for looping, this is idiomatic Racket and appropriate for this kind of problem that relies heavily on indexes:

; Returns a list of lists with all the diagonals in a square matrix
; omitting the diagonals that have a single element
; m: the matrix represented as a vector of vectors
; n: the number of rows (or columns, because it's square)
(define (diagonals m n)
; join two results
(append
; first: the leading diagonals
(for/list ([slice (in-range 1 (- (* 2 n) 2))])
(let ((z (if (< slice n) 0 (add1 (- slice n)))))
(for/list ([j (in-range z (add1 (- slice z)))])
(vector-ref (vector-ref m (sub1 (- n j))) (- slice j)))))
; second: the antidiagonals
(for/list ([slice (in-range 1 (- (* 2 n) 2))])
(let ((z (if (< slice n) 0 (add1 (- slice n)))))
(for/list ([j (in-range z (add1 (- slice z)))])
(vector-ref (vector-ref m j) (- slice j)))))))

You can test it as follows, it works as expected:

(define matrix '#(#(1 2 3 4) #(5 6 7 8) #(9 10 11 12) #(13 14 15 16)))
(diagonals matrix 4)

=> '((14 9)
(15 10 5)
(16 11 6 1)
(12 7 2)
(8 3)
(2 5)
(3 6 9)
(4 7 10 13)
(8 11 14)
(12 15))

Python 3: Get diagonal elements of matrix (list of lists) about a point in that matrix without NumPy

A bit confusing, but I think this does it:

def getDiagonals(matrix, pos):
row, col = pos
nrows = len(matrix)
ncols = len(matrix[0]) if nrows > 0 else 0
# First diagonal
d1_i, d1_j = nrows - 1 - max(row - col, 0), max(col - row, 0)
d1_len = min(d1_i + 1, ncols - d1_j)
diag1 = [matrix[d1_i - k][d1_j + k] for k in range(d1_len)]
# Second diagonal
t = min(row, ncols - col - 1)
d2_i, d2_j = nrows - 1 - row + t, col + t
d2_len = min(d2_i, d2_j) + 1
diag2 = [matrix[d2_i - k][d2_j - k] for k in range(d2_len)]
return (diag1, diag2)

# Test
matrix = [[0, 0, 0, 0, 5],
[0, 0, 0, 4, 0],
[2, 0, 3, 0, 0],
[3, 2, 0, 2, 0],
[1, 0, 2, 0, 1]]
diagonals = getDiagonals(matrix, (1, 1))
print(diagonals[0])
# [1, 2, 3, 4, 5]
print(diagonals[1])
# [2, 2, 2]

diagonals = getDiagonals(matrix, (1, 3))
print(diagonals[0])
# [2, 2, 0]
print(diagonals[1])
# [1, 2, 3, 0, 0]

diagonals = getDiagonals(matrix, (2, 2))
print(diagonals[0])
# [1, 2, 3, 4, 5]
print(diagonals[1])
# [1, 2, 3, 0, 0]

Get all the diagonals in a matrix/list of lists in Python

There are probably better ways to do it in numpy than below, but I'm not too familiar with it yet:

import numpy as np

matrix = np.array(
[[-2, 5, 3, 2],
[ 9, -6, 5, 1],
[ 3, 2, 7, 3],
[-1, 8, -4, 8]])

diags = [matrix[::-1,:].diagonal(i) for i in range(-3,4)]
diags.extend(matrix.diagonal(i) for i in range(3,-4,-1))
print [n.tolist() for n in diags]

Output

[[-2], [9, 5], [3, -6, 3], [-1, 2, 5, 2], [8, 7, 1], [-4, 3], [8], [2], [3, 1], [5, 5, 3], [-2, -6, 7, 8], [9, 2, -4], [3, 8], [-1]]

Edit: Updated to generalize for any matrix size.

import numpy as np

# Alter dimensions as needed
x,y = 3,4

# create a default array of specified dimensions
a = np.arange(x*y).reshape(x,y)
print a
print

# a.diagonal returns the top-left-to-lower-right diagonal "i"
# according to this diagram:
#
# 0 1 2 3 4 ...
# -1 0 1 2 3
# -2 -1 0 1 2
# -3 -2 -1 0 1
# :
#
# You wanted lower-left-to-upper-right and upper-left-to-lower-right diagonals.
#
# The syntax a[slice,slice] returns a new array with elements from the sliced ranges,
# where "slice" is Python's [start[:stop[:step]] format.

# "::-1" returns the rows in reverse. ":" returns the columns as is,
# effectively vertically mirroring the original array so the wanted diagonals are
# lower-right-to-uppper-left.
#
# Then a list comprehension is used to collect all the diagonals. The range
# is -x+1 to y (exclusive of y), so for a matrix like the example above
# (x,y) = (4,5) = -3 to 4.
diags = [a[::-1,:].diagonal(i) for i in range(-a.shape[0]+1,a.shape[1])]

# Now back to the original array to get the upper-left-to-lower-right diagonals,
# starting from the right, so the range needed for shape (x,y) was y-1 to -x+1 descending.
diags.extend(a.diagonal(i) for i in range(a.shape[1]-1,-a.shape[0],-1))

# Another list comp to convert back to Python lists from numpy arrays,
# so it prints what you requested.
print [n.tolist() for n in diags]

Output

[[ 0  1  2  3]
[ 4 5 6 7]
[ 8 9 10 11]]

[[0], [4, 1], [8, 5, 2], [9, 6, 3], [10, 7], [11], [3], [2, 7], [1, 6, 11], [0, 5, 10], [4, 9], [8]]

Extract diagonal of a matrix

The reason you're getting a segmentation fault is because of the way you're using copy, which you're giving invalid parameters. There's not really a way to iterate through a 2D array or vector diagonally (although if you are using a 2D array (not a vector), you can give it a start and end point diagonal from one another, but it would just copy everything in between, not just the diagonals).

I would recommend just using a for loop, there's nothing wrong with that. (Even if there is some convoluted way to get copy to work, a for loop is plenty clear and fast enough already).

#include<vector>
#include<algorithm>
#include<iostream>
#include<iterator>

int main () {

std::vector<std::vector<int>> vec {{1,2,3},{3,4,5},{1,6,7}} ;
// std::vector<int> vec1{0,0,0} ;
// std::copy ( &vec[0][0], &vec[2][2], &vec1[0] ) ;

std::vector<int> diagonal;
for(uint i=0;i<vec.size();i++){
diagonal.push_back(vec[i][i]);
}

}


Related Topics



Leave a reply



Submit