Diagonales principales
La lista de las diagonales principales de la matriz
1 2 3 4 5 6 7 8 9 10 11 12
es
[[9],[5,10],[1,6,11],[2,7,12],[3,8],[4]]
Definir la función
diagonalesPrincipales :: Array (Int,Int) a -> [[a]]
tal que (diagonalesPrincipales p)
es la lista de las diagonales principales de p
. Por ejemplo,
λ> diagonalesPrincipales (listArray ((1,1),(3,4)) [1..12]) [[9],[5,10],[1,6,11],[2,7,12],[3,8],[4]]
Nota: Escribir las soluciones en Haskell, en Python y en Common Lisp.
Soluciones
A continuación se muestran
- las soluciones en Haskell,
- las soluciones en Python y
- las soluciones en Common Lisp
1. Soluciones en Haskell
import Data.Array (Array, (!), bounds, listArray) import Test.Hspec (Spec, describe, hspec, it, shouldBe) import Test.QuickCheck -- 1ª solución -- =========== diagonalesPrincipales1 :: Array (Int,Int) a -> [[a]] diagonalesPrincipales1 p = [[p ! ij | ij <- ijs] | ijs <- posicionesDiagonalesPrincipales1 m n] where (_,(m,n)) = bounds p posicionesDiagonalesPrincipales1 :: Int -> Int -> [[(Int, Int)]] posicionesDiagonalesPrincipales1 m n = [extension ij | ij <- iniciales] where iniciales = [(i,1) | i <- [m,m-1..2]] ++ [(1,j) | j <- [1..n]] extension (i,j) = [(i+k,j+k) | k <- [0..min (m-i) (n-j)]] -- 2ª solución -- =========== diagonalesPrincipales2 :: Array (Int,Int) a -> [[a]] diagonalesPrincipales2 p = [[p ! ij | ij <- ijs] | ijs <- posicionesDiagonalesPrincipales2 m n] where (_,(m,n)) = bounds p posicionesDiagonalesPrincipales2 :: Int -> Int -> [[(Int, Int)]] posicionesDiagonalesPrincipales2 m n = [zip [i..m] [1..n] | i <- [m,m-1..1]] ++ [zip [1..m] [j..n] | j <- [2..n]] -- Verificación -- ============ verifica :: IO () verifica = hspec spec specG :: (Array (Int,Int) Int -> [[Int]]) -> Spec specG diagonalesPrincipales = do it "e1" $ diagonalesPrincipales (listArray ((1,1),(3,4)) [1..12]) `shouldBe` [[9],[5,10],[1,6,11],[2,7,12],[3,8],[4]] spec :: Spec spec = do describe "def. 1" $ specG diagonalesPrincipales1 describe "def. 2" $ specG diagonalesPrincipales2 -- La verificación es -- λ> verifica -- 2 examples, 0 failures -- Equivalencia de las definiciones -- ================================ -- La propiedad es prop_diagonalesPrincipales2 :: Positive Int -> Positive Int -> Bool prop_diagonalesPrincipales2 (Positive m) (Positive n) = diagonalesPrincipales1 p == diagonalesPrincipales2 p where p = listArray ((1,1),(m,n)) [1..] -- La comprobación es -- λ> quickCheck prop_diagonalesPrincipales2 -- +++ OK, passed 100 tests. -- Comparación de eficiencia -- ========================= -- La comparación es -- λ> length (diagonalesPrincipales1 (listArray ((1,1),(10^4,10^4)) [1..])) -- 19999 -- (6.90 secs, 8,010,369,224 bytes) -- λ> length (diagonalesPrincipales2 (listArray ((1,1),(10^4,10^4)) [1..])) -- 19999 -- (6.78 secs, 8,008,289,224 bytes)
2. Soluciones en Python
from typing import TypeVar from src.Posiciones_diagonales_principales import ( posicionesDiagonalesPrincipales1, posicionesDiagonalesPrincipales2) A = TypeVar('A') # 1ª solución # =========== matriz = list[list[A]] def diagonalesPrincipales1(p: matriz[A]) -> list[list[A]]: m = len(p) n = len(p[0]) return [[p[i-1][j-1] for (i,j) in ijs] for ijs in posicionesDiagonalesPrincipales1(m, n)] # 2ª solución # =========== def diagonalesPrincipales2(p: matriz[A]) -> list[list[A]]: m = len(p) n = len(p[0]) return [[p[i-1][j-1] for (i,j) in ijs] for ijs in posicionesDiagonalesPrincipales2(m, n)] # Verificación # ============ def test_diagonalesPrincipales() -> None: for diagonalesPrincipales in [diagonalesPrincipales1, diagonalesPrincipales2]: assert diagonalesPrincipales([[ 1, 2, 3, 4], [ 5, 6, 7, 8], [ 9,10,11,12]]) == \ [[9],[5,10],[1,6,11],[2,7,12],[3,8],[4]] print("Verificado") # La verificación es # >>> test_diagonalesPrincipales() # Verificado
2. Soluciones en Common Lisp
(ql:quickload "fiveam" :silent t) (defpackage :diagonales-principales (:use :cl :fiveam)) (in-package :diagonales-principales) ;;; 1ª solución ;;; =========== ;;; (iniciales m n) es la lista de los elementos iniciales de las ;;; posiciones de las diagonales principales de una matriz con m filas y ;;; n columnas. Por ejemplo, ;;; > (iniciales 3 4) ;;; ((3 1) (2 1) (1 1) (1 2) (1 3) (1 4)) (defun iniciales (m n) (append (loop for i from m downto 2 collect (list i 1)) (loop for j from 1 to n collect (list 1 j)))) ;;; (extension ij m n) es extension de la diagonal principal a partir de ;;; la posicion ij en una matriz de orden mxn. Por ejemplo, ;;; > (extension '(2 1) 3 4) ;;; ((2 1) (3 2)) ;;; > (extension '(1 1) 3 4) ;;; ((1 1) (2 2) (3 3)) ;;; > (extension '(2 3) 3 4) ;;; ((2 3) (3 4)) (defun extension (ij m n) (let ((i (first ij)) (j (second ij))) (loop for k from 0 to (min (- m i) (- n j)) collect (list (+ i k) (+ j k))))) ;;; (posiciones-diagonales-principales1 m n) es la lista de las posiciones ;;; de las diagonales principales de una matriz con m filas y n ;;; columnas. Por ejemplo, ;;; > (posiciones-diagonales-principales1 3 4) ;;; (((3 1)) ;;; ((2 1) (3 2)) ;;; ((1 1) (2 2) (3 3)) ;;; ((1 2) (2 3) (3 4)) ;;; ((1 3) (2 4)) ;;; ((1 4))) (defun posiciones-diagonales-principales1 (m n) (mapcar (lambda (ij) (extension ij m n)) (iniciales m n))) (defun diagonales-principales1 (p) (let* ((dimension (array-dimensions p)) (m (first dimension)) (n (second dimension))) (mapcar (lambda (ijs) (mapcar (lambda (ij) (aref p (1- (first ij)) (1- (second ij)))) ijs)) (posiciones-diagonales-principales1 m n)))) ;;; 2ª solución ;;; =========== (defun posiciones-diagonales-principales2 (m n) (append (loop for i from m downto 1 collect (loop for r from i to m for c from 1 to n collect (list r c))) (loop for j from 2 to n collect (loop for r from 1 to m for c from j to n collect (list r c))))) (defun diagonales-principales2 (p) (let* ((dimension (array-dimensions p)) (m (first dimension)) (n (second dimension))) (mapcar (lambda (ijs) (mapcar (lambda (ij) (aref p (1- (first ij)) (1- (second ij)))) ijs)) (posiciones-diagonales-principales2 m n)))) ;;; Verificación ;;; ============ (test diagonales-principales (mapc (lambda (func) (is (equal (funcall func (make-array '(3 4) :initial-contents '((1 2 3 4) (5 6 7 8) (9 10 11 12)))) '((9) (5 10) (1 6 11) (2 7 12) (3 8) (4))))) '(diagonales-principales1 diagonales-principales2))) (defun verifica () (run 'diagonales-principales)) ;;; La verificación es ;;; (diagonales-principales::verifica) ;;; Equivalencia de las definiciones ;;; ================================ ;;; (matriz-aleatoria) genera una matriz aleatoria. Por ejemplo. ;;; > (matriz-aleatoria) ;;; #2A((1 0 5) (0 5 8) (0 2 4) (5 6 9) (3 3 1) (0 5 8) (5 2 0)) ;;; DIAGONALES-PRINCIPALES> (matriz-aleatoria) ;;; #2A((8 8) (5 4) (9 5) (3 8)) (defun matriz-aleatoria () (let ((m (1+ (random 10))) (n (1+ (random 10)))) (make-array (list m n) :initial-contents (loop for i from 1 to m collect (loop for j from 1 to n collect (random 10)))))) ;;; La propiedad es (test diagonales-principales-equiv (for-all ((p 'matriz-aleatoria)) (is (equal (diagonales-principales1 p) (diagonales-principales2 p))))) (defun comprueba () (run 'diagonales-principales-equiv)) ;;; La comprobación es ;;; > (diagonales-principales::comprueba) ;;; ;;; Running test DIAGONALES-PRINCIPALES-EQUIV ... ;;; Comparación de eficiencia ;;; ========================= ;;; La comparación es ;;; > (setf ejemplo (make-array '(3000 2000) :initial-element 0)) ;;; > (time (length (diagonales-principales1 ejemplo))) ;;; 0.829 seconds of real time ;;; > (time (length (diagonales-principales2 ejemplo))) ;;; 1.017 seconds of real time