Posiciones de las diagonales principales
Las posiciones de una matriz con 3 filas y 4 columnas son
(1,1) (1,2) (1,3) (1,4) (2,1) (2,2) (2,3) (2,4) (3,1) (3,2) (3,3) (3,4)
Las posiciones de sus 6 diagonales principales son
[(3,1)] [(2,1),(3,2)] [(1,1),(2,2),(3,3)] [(1,2),(2,3),(3,4)] [(1,3),(2,4)] [(1,4)]
Definir la función
posicionesDiagonalesPrincipales :: Int -> Int -> [[(Int, Int)]]
tal que (posicionesdiagonalesprincipales m n)
es la lista de las posiciones de las diagonales principales de una matriz con m
filas y n
columnas. Por ejemplo,
λ> mapM_ print (posicionesDiagonalesPrincipales 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)] λ> mapM_ print (posicionesDiagonalesPrincipales 4 4) [(4,1)] [(3,1),(4,2)] [(2,1),(3,2),(4,3)] [(1,1),(2,2),(3,3),(4,4)] [(1,2),(2,3),(3,4)] [(1,3),(2,4)] [(1,4)] λ> mapM_ print (posicionesDiagonalesPrincipales 4 3) [(4,1)] [(3,1),(4,2)] [(2,1),(3,2),(4,3)] [(1,1),(2,2),(3,3)] [(1,2),(2,3)] [(1,3)]
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 Test.Hspec (Spec, describe, hspec, it, shouldBe) import Test.QuickCheck -- 1ª solución -- =========== 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 -- =========== 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 :: (Int -> Int -> [[(Int, Int)]]) -> Spec specG posicionesDiagonalesPrincipales = do it "e1" $ posicionesDiagonalesPrincipales 3 4 `shouldBe` [[(3,1)], [(2,1),(3,2)], [(1,1),(2,2),(3,3)], [(1,2),(2,3),(3,4)], [(1,3),(2,4)], [(1,4)]] it "e2" $ posicionesDiagonalesPrincipales 4 4 `shouldBe` [[(4,1)], [(3,1),(4,2)], [(2,1),(3,2),(4,3)], [(1,1),(2,2),(3,3),(4,4)], [(1,2),(2,3),(3,4)], [(1,3),(2,4)], [(1,4)]] it "e3" $ posicionesDiagonalesPrincipales 4 3 `shouldBe` [[(4,1)], [(3,1),(4,2)], [(2,1),(3,2),(4,3)], [(1,1),(2,2),(3,3)], [(1,2),(2,3)], [(1,3)]] spec :: Spec spec = do describe "def. 1" $ specG posicionesDiagonalesPrincipales1 describe "def. 2" $ specG posicionesDiagonalesPrincipales2 -- La verificación es -- λ> verifica -- 6 examples, 0 failures -- Equivalencia de las definiciones -- ================================ -- La propiedad es prop_posicionesDiagonalesPrincipales_equiv :: Positive Int -> Positive Int -> Bool prop_posicionesDiagonalesPrincipales_equiv (Positive m) (Positive n) = posicionesDiagonalesPrincipales1 m n == posicionesDiagonalesPrincipales2 m n -- La comprobación es -- λ> quickCheck prop_posicionesDiagonalesPrincipales_equiv -- +++ OK, passed 100 tests. -- Comparación de eficiencia -- ========================= -- La comparación es -- λ> length (posicionesDiagonalesPrincipales1 (10^7) (10^6)) -- 10999999 -- (6.14 secs, 3,984,469,440 bytes) -- λ> length (posicionesDiagonalesPrincipales2 (10^7) (10^6)) -- 10999999 -- (3.07 secs, 2,840,469,440 bytes)
2. Soluciones en Python
from timeit import Timer, default_timer from hypothesis import given from hypothesis import strategies as st # 1ª solución # =========== matriz = list[list[tuple[int, int]]] def posicionesDiagonalesPrincipales1(m: int, n: int) -> matriz: def iniciales() -> list[tuple[int, int]]: return [(i,1) for i in range(m,1,-1)] + [(1,j) for j in range(1, n+1)] def extension(p: tuple[int, int]) -> list[tuple[int, int]]: (i,j) = p return [(i+k,j+k) for k in range(0, 1+min(m-i, n-j))] return [extension(ij) for ij in iniciales()] # 2ª solución # =========== def posicionesDiagonalesPrincipales2(m: int, n: int) -> matriz: return [list(zip(range(i,m+1), range(1,n+1))) for i in range(m,0,-1)] + \ [list(zip(range(1,m+1), range(j,n+1))) for j in range(2,n+1)] # Verificación # ============ def test_posicionesDiagonalesPrincipales() -> None: for posicionesDiagonalesPrincipales in [posicionesDiagonalesPrincipales1, posicionesDiagonalesPrincipales2]: assert posicionesDiagonalesPrincipales(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)]] assert posicionesDiagonalesPrincipales(4, 4) == \ [[(4,1)], [(3,1),(4,2)], [(2,1),(3,2),(4,3)], [(1,1),(2,2),(3,3),(4,4)], [(1,2),(2,3),(3,4)], [(1,3),(2,4)], [(1,4)]] assert posicionesDiagonalesPrincipales(4, 3) == \ [[(4,1)], [(3,1),(4,2)], [(2,1),(3,2),(4,3)], [(1,1),(2,2),(3,3)], [(1,2),(2,3)], [(1,3)]] print("Verificado") # La verificación es # >>> test_posicionesDiagonalesPrincipales() # Verificado # Equivalencia de las definiciones # ================================ # La propiedad es @given(st.integers(min_value=1, max_value=100), st.integers(min_value=1, max_value=100)) def test_posicionesDiagonalesPrincipales_equiv(m: int, n: int) -> None: assert posicionesDiagonalesPrincipales1(m, n) == \ posicionesDiagonalesPrincipales2(m, n) # La comprobación es # >>> test_posicionesDiagonalesPrincipales_equiv() # >>> # Comparación de eficiencia # ========================= def tiempo(e: str) -> None: """Tiempo (en segundos) de evaluar la expresión e.""" t = Timer(e, "", default_timer, globals()).timeit(1) print(f"{t:0.2f} segundos") # La comparación es # >>> tiempo('posicionesDiagonalesPrincipales1(10**4, 2*10**3)') # 3.32 segundos # >>> tiempo('posicionesDiagonalesPrincipales2(10**4, 2*10**3)') # 2.16 segundos
2. Soluciones en Common Lisp
(ql:quickload "fiveam" :silent t) (defpackage :posiciones-diagonales-principales (:use :cl :fiveam)) (in-package :posiciones-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))))) (defun posiciones-diagonales-principales-1 (m n) (mapcar (lambda (ij) (extension ij m n)) (iniciales m n))) ;;; 2ª solución ;;; =========== (defun posiciones-diagonales-principales-2 (m n) (flet ((iniciales () (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) (let ((i (first ij)) (j (second ij))) (loop for k from 0 to (min (- m i) (- n j)) collect (list (+ i k) (+ j k)))))) (mapcar (lambda (ij) (extension ij)) (iniciales)))) ;;; 3ª definición ;;; ============= (defun posiciones-diagonales-principales-3 (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 posiciones-diagonales-principales-4 (m n) (let ((iniciales (append (loop for i from m downto 2 collect (list i 1)) (loop for j from 1 to n collect (list 1 j)))) (result '())) (dolist (ij iniciales result) (let* ((i (first ij)) (j (second ij)) (lim (min (- m i) (- n j))) (diagonal (loop for k from 0 to lim collect (list (+ i k) (+ j k))))) (push diagonal result))) (nreverse result))) ;;; Verificación ;;; ============ (test posiciones-diagonales-principales (mapc (lambda (func) (is (equal (funcall func 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))))) (is (equal (funcall func '4 4) '(((4 1)) ((3 1) (4 2)) ((2 1) (3 2) (4 3)) ((1 1) (2 2) (3 3) (4 4)) ((1 2) (2 3) (3 4)) ((1 3) (2 4)) ((1 4))))) (is (equal (funcall func '4 3) '(((4 1)) ((3 1) (4 2)) ((2 1) (3 2) (4 3)) ((1 1) (2 2) (3 3)) ((1 2) (2 3)) ((1 3)))))) '(posiciones-diagonales-principales-1 posiciones-diagonales-principales-2 posiciones-diagonales-principales-3 posiciones-diagonales-principales-4))) (defun verifica () (run 'posiciones-diagonales-principales)) ;;; La verificación es ;;; > (posiciones-diagonales-principales::verifica) ;;; ;;; Running test POSICIONES-DIAGONALES-PRINCIPALES ......... ;;; Equivalencia de las definiciones ;;; ================================ ;;; La propiedad es (test posiciones-diagonales-principales-equiv (for-all ((m (gen-integer :min 1 :max 20)) (n (gen-integer :min 1 :max 20))) (let ((res (posiciones-diagonales-principales-1 m n))) (is (equal (posiciones-diagonales-principales-2 m n) res)) (is (equal (posiciones-diagonales-principales-3 m n) res)) (is (equal (posiciones-diagonales-principales-4 m n) res))))) (defun comprueba () (run 'posiciones-diagonales-principales-equiv)) ;;; La comprobación es ;;; > (posiciones-diagonales-principales::comprueba) ;;; ;;; Running test POSICIONES-DIAGONALES-PRINCIPALES-EQUIV ... ;;; (#<IT.BESE.FIVEAM::FOR-ALL-TEST-PASSED {10030E76B3}>) ;;; Comparación de eficiencia ;;; ========================= ;;; La comparación es ;;; > (time (length (posiciones-diagonales-principales-1 3000 2000))) ;;; 0.453 seconds of real time ;;; > (time (length (posiciones-diagonales-principales-2 3000 2000))) ;;; 0.807 seconds of real time ;;; > (time (length (posiciones-diagonales-principales-3 3000 2000))) ;;; 0.440 seconds of real time ;;; > (time (length (posiciones-diagonales-principales-4 3000 2000))) ;;; 0.672 seconds of real time