Ir al contenido principal

Suma elementos consecutivos

Definir la función

   sumaConsecutivos :: [Integer] -> [Integer]

tal que sumaConsecutivos xs es la suma de los pares de elementos consecutivos de la lista xs. Por ejemplo,

   sumaConsecutivos [3,1,5,2]  ==  [4,6,7]
   sumaConsecutivos [3]        ==  []
   last (sumaConsecutivos [1..10^8])  ==  199999999

Soluciones

A continuación se muestran las soluciones en Haskell y las soluciones en Python.

Soluciones en Haskell

import Test.QuickCheck

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

sumaConsecutivos1 :: [Integer] -> [Integer]
sumaConsecutivos1 xs = [x+y | (x,y) <- zip xs (tail xs)]

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

sumaConsecutivos2 :: [Integer] -> [Integer]
sumaConsecutivos2 xs = zipWith (+) xs (tail xs)

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

sumaConsecutivos3 :: [Integer] -> [Integer]
sumaConsecutivos3 = zipWith (+) <*> tail

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

sumaConsecutivos4 :: [Integer] -> [Integer]
sumaConsecutivos4 (x:y:zs) = x+y : sumaConsecutivos4 (y:zs)
sumaConsecutivos4 _        = []

-- Comprobación de equivalencia
-- ============================

-- La propiedad es
prop_sumaConsecutivos :: [Integer] -> Bool
prop_sumaConsecutivos xs =
  all (== sumaConsecutivos1 xs)
      [sumaConsecutivos2 xs,
       sumaConsecutivos3 xs,
       sumaConsecutivos4 xs]

-- La comprobación es
--    λ> quickCheck prop_sumaConsecutivos
--    +++ OK, passed 100 tests.

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

-- La comparación es
--    λ> last (sumaConsecutivos1 [1..8*10^6])
--    15999999
--    (1.98 secs, 2,176,566,784 bytes)
--    λ> last (sumaConsecutivos2 [1..8*10^6])
--    15999999
--    (0.19 secs, 1,408,566,840 bytes)
--    λ> last (sumaConsecutivos3 [1..8*10^6])
--    15999999
--    (0.19 secs, 1,408,566,936 bytes)
--    λ> last (sumaConsecutivos4 [1..8*10^6])
--    15999999
--    (2.78 secs, 2,560,566,832 bytes)

El código se encuentra en GitHub.

Soluciones en Python

from operator import add
from sys import setrecursionlimit
from timeit import Timer, default_timer

from hypothesis import given
from hypothesis import strategies as st

setrecursionlimit(10**6)

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

def sumaConsecutivos1(xs: list[int]) -> list[int]:
    return [x + y for (x, y) in zip(xs, xs[1:])]

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

def sumaConsecutivos2(xs: list[int]) -> list[int]:
    return list(map(add, xs, xs[1:]))

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

def sumaConsecutivos3(xs: list[int]) -> list[int]:
    if len(xs) >= 2:
        return [xs[0] + xs[1]] + sumaConsecutivos3(xs[1:])
    return []

# Comprobación de equivalencia
# ============================

# La propiedad es
@given(st.lists(st.integers(min_value=1, max_value=100)))
def test_sumaConsecutivos(xs: list[int]) -> None:
    r = sumaConsecutivos1(xs)
    assert sumaConsecutivos2(xs) == r
    assert sumaConsecutivos3(xs) == r

# La comprobación es
#    src> poetry run pytest -q suma_elementos_consecutivos.py
#    1 passed in 0.26s

# 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('sumaConsecutivos1(range(1, 10**4))')
#    0.00 segundos
#    >>> tiempo('sumaConsecutivos2(range(1, 10**4))')
#    0.00 segundos
#    >>> tiempo('sumaConsecutivos3(range(1, 10**4))')
#    0.18 segundos
#
#    >>> tiempo('sumaConsecutivos1(range(1, 10**8))')
#    8.34 segundos
#    >>> tiempo('sumaConsecutivos2(range(1, 10**8))')
#    6.28 segundos

El código se encuentra en GitHub.