Ir al contenido principal

Suma de cadenas


Definir la función

sumaCadenas :: String -> String -> String

tal que (sumaCadenas xs ys) es la cadena formada por el número entero que es la suma de los números enteros cuyas cadenas que lo representan son xs e ys; además, se supone que la cadena vacía representa al cero. Por ejemplo,

sumaCadenas "2"   "6"  == "8"
sumaCadenas "14"  "2"  == "16"
sumaCadenas "14"  "-5" == "9"
sumaCadenas "-14" "-5" == "-19"
sumaCadenas "5"   "-5" == "0"
sumaCadenas ""    "5"  == "5"
sumaCadenas "6"   ""   == "6"
sumaCadenas ""    ""   == "0"

Nota: Escribir las soluciones en Haskell, en Python y en Common Lisp.

Soluciones

A continuación se muestran

1. Soluciones en Haskell

import Test.Hspec (Spec, describe, hspec, it, shouldBe)
import Test.QuickCheck

-- 1ª solución
-- ===========

sumaCadenas1 :: String -> String -> String
sumaCadenas1 xs ys = show (numero xs + numero ys)

-- (numero xs) es el número entero representado por la cadena xs
-- suponiendo que la cadena vacía representa al cero.. Por ejemplo,
--    numero "12"   ==  12
--    numero "-12"  ==  -12
--    numero "0"    ==  0
--    numero ""     ==  0
numero :: String -> Int
numero "" = 0
numero xs = read xs

-- 2ª solución
-- ===========

sumaCadenas2 :: String -> String -> String
sumaCadenas2 "" "" = "0"
sumaCadenas2 "" ys = ys
sumaCadenas2 xs "" = xs
sumaCadenas2 xs ys = show (read xs + read ys)

-- 3ª solución
-- ===========

sumaCadenas3 :: String -> String -> String
sumaCadenas3 xs ys =
  show (sum (map read (filter (not . null) [xs, ys])))

-- 4ª solución
-- ===========

sumaCadenas4 :: String -> String -> String
sumaCadenas4 =
  ((show . sum . map read . filter (not . null)) .) . (. return) . (:)

-- Verificación
-- ============

verifica :: IO ()
verifica = hspec spec

specG :: (String -> String -> String) -> Spec
specG sumaCadenas = do
  it "e1" $
    sumaCadenas "2"   "6"  `shouldBe` "8"
  it "e2" $
    sumaCadenas "14"  "2"  `shouldBe` "16"
  it "e3" $
    sumaCadenas "14"  "-5" `shouldBe` "9"
  it "e4" $
    sumaCadenas "-14" "-5" `shouldBe` "-19"
  it "e5" $
    sumaCadenas "5"   "-5" `shouldBe` "0"
  it "e6" $
    sumaCadenas ""    "5"  `shouldBe` "5"
  it "e7" $
    sumaCadenas "6"   ""   `shouldBe` "6"
  it "e8" $
    sumaCadenas ""    ""   `shouldBe` "0"

spec :: Spec
spec = do
  describe "def. 1" $ specG sumaCadenas1
  describe "def. 2" $ specG sumaCadenas2
  describe "def. 3" $ specG sumaCadenas3
  describe "def. 4" $ specG sumaCadenas4

-- La verificación es
--    λ> verifica
--
--    32 examples, 0 failures

-- Equivalencia de las definiciones
-- ================================

-- La propiedad es
prop_sumaCadenas :: Int -> Int -> Bool
prop_sumaCadenas x y =
  all (== sumaCadenas1 xs ys)
      [sumaCadenas2 xs ys,
       sumaCadenas3 xs ys,
       sumaCadenas4 xs ys]
  where xs = show x
        ys = show y

-- La comparación es
--    λ> quickCheck prop_sumaCadenas
--    +++ OK, passed 100 tests.

-- Comparación de eficiencia
-- =========================

-- La comparación es
--    λ> sumaCadenas1 (show (10^10000)) ('-' : show (10^10000))
--    "0"
--    (0.03 secs, 7,814,456 bytes)
--    λ> sumaCadenas2 (show (10^10000)) ('-' : show (10^10000))
--    "0"
--    (0.03 secs, 7,814,360 bytes)
--    λ> sumaCadenas3 (show (10^10000)) ('-' : show (10^10000))
--    "0"
--    (0.03 secs, 7,814,936 bytes)
--    λ> sumaCadenas4 (show (10^10000)) ('-' : show (10^10000))
--    "0"
--    (0.03 secs, 7,814,872 bytes)

2. Soluciones en Python

# 1ª solución
# ===========

# numero(xs) es el número entero representado por la cadena xs
# suponiendo que la cadena vacía representa al cero.. Por ejemplo,
#    numero "12"   ==  12
#    numero "-12"  ==  -12
#    numero "0"    ==  0
#    numero ""     ==  0
def numero(s: str) -> int:
    if not s:
        return 0
    return int(s)

def sumaCadenas1(xs: str, ys: str) -> str:
    return str(numero(xs) + numero(ys))

# 2ª solución
# ===========

def sumaCadenas2(xs: str, ys: str) -> str:
    if xs == "" and ys == "":
        return "0"
    if xs == "":
        return ys
    if ys == "":
        return xs
    return str(int(xs) + int(ys))

# 3ª solución
# ===========

def sumaCadenas3(xs: str, ys: str) -> str:
    x = int(xs or "0")
    y = int(ys or "0")
    return str(x + y)

# 4ª solución
# ===========

def sumaCadenas4(xs: str, ys: str) -> str:
    return str(sum(map(int, filter(lambda x: x != '', [xs, ys]))))

# Verificación
# ============

def test_sumaCadenas() -> None:
    for sumaCadenas in [sumaCadenas1, sumaCadenas2, sumaCadenas3,
                        sumaCadenas4]:
        assert sumaCadenas("2",   "6")  == "8"
        assert sumaCadenas("14",  "2")  == "16"
        assert sumaCadenas("14",  "-5") == "9"
        assert sumaCadenas("-14", "-5") == "-19"
        assert sumaCadenas("5",   "-5") == "0"
        assert sumaCadenas("",    "5")  == "5"
        assert sumaCadenas("6",   "")   == "6"
        assert sumaCadenas("",    "")   == "0"
    print("Verificado")

# La verificación es
#    >>> test_sumaCadenas()
#    Verificado

3. Soluciones en Common Lisp

(ql:quickload "fiveam" :silent t)

(defpackage :suma-de-cadenas
  (:use :cl
        :fiveam))

(in-package :suma-de-cadenas)

;;; 1ª solución
;;; ===========

;;; (numero xs) es el número entero representado por la cadena xs
;;; suponiendo que la cadena vacía representa al cero.. Por ejemplo,
;;;    (numero "12")   ==  12
;;;    (numero "-12")  ==  -12
;;;    (numero "0")    ==  0
;;;    (numero "")     ==  0
(defun numero (s)
  (if (string= s "")
      0
      (parse-integer s)))

(defun suma-cadenas1 (xs ys)
  (write-to-string (+ (numero xs) (numero ys))))

;;; 2ª solución
;;; ===========

(defun suma-cadenas2 (xs ys)
  (cond
    ((and (string= xs "") (string= ys "")) "0")
    ((string= xs "") ys)
    ((string= ys "") xs)
    (t (write-to-string (+ (parse-integer xs) (parse-integer ys))))))

;;; 3ª solución
;;; ===========

(defun suma-cadenas3 (xs ys)
  (write-to-string
   (reduce #'+
           (mapcar #'parse-integer
                   (remove-if (lambda (zs) (string= zs "")) (list xs ys)))
           :initial-value 0)))

;;; Verificación
;;; ============

(test suma-cadenas
  (mapc (lambda (suma-cadenas)
          (is (equal (funcall suma-cadenas "2"   "6")  "8"))
          (is (equal (funcall suma-cadenas "14"  "2")  "16"))
          (is (equal (funcall suma-cadenas "14"  "-5") "9"))
          (is (equal (funcall suma-cadenas "-14" "-5") "-19"))
          (is (equal (funcall suma-cadenas "5"   "-5") "0"))
          (is (equal (funcall suma-cadenas ""    "5")  "5"))
          (is (equal (funcall suma-cadenas "6"   "")   "6"))
          (is (equal (funcall suma-cadenas ""    "")   "0")) )
        '(suma-cadenas1
          suma-cadenas2
          suma-cadenas3)))

(defun verifica ()
  (run! 'suma-cadenas))

;;; La verificación es
;;;    (verifica)
;;;
;;;    Running test SUMA-CADENAS ........

;;; Equivalencia de las definiciones
;;; ================================

;;; La propiedad es
(test suma-cadenas-equiv
  (for-all ((x (gen-integer))
            (y (gen-integer)))
    (let ((xs (write-to-string x))
          (ys (write-to-string y)))
      (is (string= (suma-cadenas1 xs ys)
                   (suma-cadenas2 xs ys)))
      (is (string= (suma-cadenas1 xs ys)
                   (suma-cadenas2 xs ys))))))

(defun comprueba ()
  (run 'suma-cadenas-equiv))

;;; La comprobación es
;;;    > (comprueba)
;;;
;;;    Running test SUMA-CADENAS-EQUIV ...

;;; Comparación de eficiencia
;;; =========================

;;; La comparación es
;;;    > (defvar c1 (write-to-string (expt 10 10000)))
;;;    > (defvar c2 (write-to-string (- (expt 10 10000))))
;;;    > (time (suma-cadenas1 c1 c2))
;;;    0.050 seconds of real time
;;;    > (time (suma-cadenas2 c1 c2))
;;;    0.051 seconds of real time
;;;    > (time (suma-cadenas3 c1 c2))
;;;    0.036 seconds of real time