{"id":7840,"date":"2022-11-12T10:46:32","date_gmt":"2022-11-12T09:46:32","guid":{"rendered":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/?p=7840"},"modified":"2022-11-12T10:46:53","modified_gmt":"2022-11-12T09:46:53","slug":"12-nov-22","status":"publish","type":"post","link":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/12-nov-22\/","title":{"rendered":"PFH: La semana en Exercitium (11 de noviembre de 2022)"},"content":{"rendered":"<p>Esta semana he publicado en <a href=\"http:\/\/bit.ly\/2sqPtGs\">Exercitium<\/a> las soluciones de los siguientes problemas:<\/p>\n<ul>\n<li><a href=\"#ej1\">1. N\u00fameros de Lychrel<\/a><\/li>\n<li><a href=\"#ej2\">2. Suma de los d\u00edgitos de una cadena<\/a><\/li>\n<li><a href=\"#ej3\">3. Poner en may\u00fascula la primera letra y las restantes en min\u00fasculas<\/a><\/li>\n<li><a href=\"#ej4\">4. May\u00fasculas iniciales<\/a><\/li>\n<li><a href=\"#ej5\">5. Posiciones de un car\u00e1cter en una cadena<\/a><\/li>\n<\/ul>\n<p>A continuaci\u00f3n se muestran las soluciones.<br \/>\n<!--more--><br \/>\n<a name=\"ej1\"><\/a><\/p>\n<h3>1. N\u00fameros de Lychrel<\/h3>\n<p>Un <a href=\"http:\/\/bit.ly\/2X4DzMf\">n\u00famero de Lychrel<\/a> es un n\u00famero  para el que nunca se obtiene un capic\u00faa mediante el proceso de invertir las cifras y sumar los dos n\u00fameros. Por ejemplo, los siguientes n\u00fameros no son n\u00fameros de Lychrel:<\/p>\n<ul>\n<li>56, ya que en un paso se obtiene un capic\u00faa: 56+65=121.<\/li>\n<li>57, ya que en dos pasos se obtiene un capic\u00faa: 57+75=132, 132+231=363<\/li>\n<li>59, ya que en dos pasos se obtiene un capic\u00faa: 59+95=154, 154+451=605, 605+506=1111<\/li>\n<li>89, ya que en 24 pasos se obtiene un capic\u00faa.<\/li>\n<\/ul>\n<p>En esta serie de ejercicios vamos a buscar el primer n\u00famero de Lychrel.<\/p>\n<p><strong>Ejercicio 1.<\/strong> Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   esCapicua :: Integer -> Bool\n<\/pre>\n<p>tal que <code>esCapicua x<\/code> se verifica si <code>x<\/code> es capic\u00faa. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   esCapicua 252  ==  True\n   esCapicua 253  ==  False\n<\/pre>\n<p><strong>Ejercicio 2.<\/strong> Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   inverso :: Integer -> Integer\n<\/pre>\n<p>tal que <code>inverso x<\/code> es el n\u00famero obtenido escribiendo las cifras de <code>x<\/code> en orden inverso. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   inverso 253  ==  352\n<\/pre>\n<p><strong>Ejercicio 3.<\/strong> Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   siguiente :: Integer -> Integer\n<\/pre>\n<p>tal que <code>siguiente x<\/code> es el n\u00famero obtenido sum\u00e1ndole a <code>x<\/code> su inverso. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   siguiente 253  ==  605\n<\/pre>\n<p><strong>Ejercicio 4.<\/strong> Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   busquedaDeCapicua :: Integer -> [Integer]\n<\/pre>\n<p>tal que <code>busquedaDeCapicua x<\/code> es la lista de los n\u00fameros tal que el primero es <code>x<\/code>, el segundo es el siguiente de <code>x<\/code> y as\u00ed sucesivamente hasta que se alcanza un capic\u00faa. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   busquedaDeCapicua 253  ==  [253,605,1111]\n<\/pre>\n<p><strong>Ejercicio 5.<\/strong> Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   capicuaFinal :: Integer -> Integer\n<\/pre>\n<p>tal que <code>capicuaFinal x<\/code> es la capic\u00faa con la que termina la b\u00fasqueda de capic\u00faa a partir de <code>x<\/code>. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   capicuaFinal 253  ==  1111\n<\/pre>\n<p><strong>Ejercicio 6.<\/strong> Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   orden :: Integer -> Integer\n<\/pre>\n<p>tal que <code>orden x<\/code> es el n\u00famero de veces que se repite el proceso de calcular el inverso a partir de <code>x<\/code> hasta alcanzar un n\u00famero capic\u00faa. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   orden 253  ==  2\n<\/pre>\n<p><strong>Ejercicio 7.<\/strong> Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   ordenMayor :: Integer -> Integer -> Bool\n<\/pre>\n<p>tal que <code>ordenMayor x n<\/code> se verifica si el orden de <code>x<\/code> es mayor o igual que <code>n<\/code>. Dar la definici\u00f3n sin necesidad de evaluar el orden de <code>x<\/code>. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   \u03bb> ordenMayor 1186060307891929990 2\n   True\n   \u03bb> orden 1186060307891929990\n   261\n<\/pre>\n<p><strong>Ejercicio 8.<\/strong> Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   ordenEntre :: Integer -> Integer -> [Integer]\n<\/pre>\n<p>tal que <code>ordenEntre m n<\/code> es la lista de los elementos cuyo orden esmayor o igual que <code>m<\/code> y menor que <code>n<\/code>. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   take 5 (ordenEntre 10 11)  ==  [829,928,9059,9149,9239]\n<\/pre>\n<p><strong>Ejercicio 9.<\/strong> Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   menorDeOrdenMayor :: Integer -> Integer\n<\/pre>\n<p>tal que <code>menorDeOrdenMayor n<\/code> es el menor elemento cuyo orden es mayor que <code>n<\/code>. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   menorDeOrdenMayor 2   ==  19\n   menorDeOrdenMayor 20  ==  89\n<\/pre>\n<p><strong>Ejercicio 10.<\/strong> Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   menoresdDeOrdenMayor :: Integer -> [(Integer,Integer)]\n<\/pre>\n<p>tal que <code>menoresdDeOrdenMayor m<\/code> es la lista de los pares <code>(n,x)<\/code> tales que <code>n<\/code> es un n\u00famero entre 1 y <code>m<\/code> y <code>x<\/code> es el menor elemento de orden mayor que <code>n<\/code>. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   menoresdDeOrdenMayor 5  ==  [(1,10),(2,19),(3,59),(4,69),(5,79)]\n<\/pre>\n<p><strong>Ejercicio 11.<\/strong> A la vista de los resultados de <code>menoresdDeOrdenMayor 5<\/code> conjeturar sobre la \u00faltima cifra de <code>menorDeOrdenMayor<\/code>.<\/p>\n<p><strong>Ejercicio 12.<\/strong> Decidir con QuickCheck la conjetura.<\/p>\n<p><strong>Ejercicio 13.<\/strong> Calcular <code>menoresdDeOrdenMayor 50<\/code><\/p>\n<p><strong>Ejercicio 14.<\/strong> A la vista de <code>menoresdDeOrdenMayor 50<\/code>, conjeturar el orden de 196.<\/p>\n<p><strong>Ejercicio 15.<\/strong> Comprobar con QuickCheck la conjetura sobre el orden de 196.<\/p>\n<p><b>1.1. Soluciones en Haskell<\/b><\/p>\n<pre lang=\"haskell\">\nimport Test.QuickCheck\n\n-- Soluci\u00f3n de ejercicio 1\nesCapicua :: Integer -> Bool\nesCapicua x = x' == reverse x'\n  where x' = show x\n\n-- Soluci\u00f3n de ejercicio 2\ninverso :: Integer -> Integer\ninverso = read . reverse . show\n\n-- Soluci\u00f3n de ejercicio 3\nsiguiente :: Integer -> Integer\nsiguiente x = x + inverso x\n\n-- Soluci\u00f3n de ejercicio 4\nbusquedaDeCapicua :: Integer -> [Integer]\nbusquedaDeCapicua x | esCapicua x = [x]\n                    | otherwise   = x : busquedaDeCapicua (siguiente x)\n\n-- Soluci\u00f3n de ejercicio 5\ncapicuaFinal :: Integer -> Integer\ncapicuaFinal x = last (busquedaDeCapicua x)\n\n-- Soluci\u00f3n de ejercicio 6\norden :: Integer -> Integer\norden x | esCapicua x = 0\n        | otherwise   = 1 + orden (siguiente x)\n\n-- Soluci\u00f3n de ejercicio 7\nordenMayor :: Integer -> Integer -> Bool\nordenMayor x n | esCapicua x = n == 0\n               | n <= 0      = True\n               | otherwise   = ordenMayor (siguiente x) (n-1)\n\n-- Soluci\u00f3n de ejercicio 8\nordenEntre :: Integer -> Integer -> [Integer]\nordenEntre m n = [x | x <- [1..], ordenMayor x m, not (ordenMayor x n)]\n\n-- Soluci\u00f3n de ejercicio 9\nmenorDeOrdenMayor :: Integer -> Integer\nmenorDeOrdenMayor n = head [x | x <- [1..], ordenMayor x n]\n\n-- Soluci\u00f3n de ejercicio 10\nmenoresdDeOrdenMayor :: Integer -> [(Integer,Integer)]\nmenoresdDeOrdenMayor m = [(n,menorDeOrdenMayor n) | n <- [1..m]]\n\n-- Soluci\u00f3n de ejercicio 11\n-- La conjetura es que para n mayor que 1, la \u00faltima cifra de\n-- (menorDeOrdenMayor n) es 9.\n\n-- Soluci\u00f3n de ejercicio 12\n-- ========================\n\n-- La conjetura es\nprop_menorDeOrdenMayor :: Integer -> Property\nprop_menorDeOrdenMayor n =\n  n > 1 ==> menorDeOrdenMayor n `mod` 10 == 9\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheck prop_menorDeOrdenMayor\n--    *** Failed! Falsifiable (after 22 tests and 2 shrinks):\n--    25\n\n-- Se puede comprobar que 25 es un contraejemplo,\n--    \u03bb> menorDeOrdenMayor 25\n--    196\n\n-- Soluci\u00f3n de ejercicio 13\n-- El c\u00e1lculo es\n--    \u03bb> menoresdDeOrdenMayor 50\n--    [(1,10),(2,19),(3,59),(4,69),(5,79),(6,79),(7,89),(8,89),(9,89),\n--     (10,89),(11,89),(12,89),(13,89),(14,89),(15,89),(16,89),(17,89),\n--     (18,89),(19,89),(20,89),(21,89),(22,89),(23,89),(24,89),(25,196),\n--     (26,196),(27,196),(28,196),(29,196),(30,196),(31,196),(32,196),\n--     (33,196),(34,196),(35,196),(36,196),(37,196),(38,196),(39,196),\n--     (40,196),(41,196),(42,196),(43,196),(44,196),(45,196),(46,196),\n--     (47,196),(48,196),(49,196),(50,196)]\n\n-- Soluci\u00f3n de ejercicio 14\n-- La conjetura es que el orden de 196 es infinito y, por tanto,\n-- 196 es un n\u00famero del Lychrel.\n\n-- Soluci\u00f3n de ejercicio 15\n-- ========================\n\n-- La propiedad es\nprop_ordenDe196 :: Integer -> Bool\nprop_ordenDe196 n =\n  ordenMayor 196 n\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheck prop_ordenDe196\n--    +++ OK, passed 100 tests.\n<\/pre>\n<p><b>1.2. Soluciones en Python<\/b><\/p>\n<pre lang=\"python\">\nfrom itertools import islice\nfrom sys import setrecursionlimit\nfrom typing import Generator, Iterator\n\nfrom hypothesis import given, settings\nfrom hypothesis import strategies as st\n\nsetrecursionlimit(10**6)\n\n# Soluci\u00f3n del ejercicio 1\ndef esCapicua(x: int) -> bool:\n    return x == int(str(x)[::-1])\n\n# Soluci\u00f3n del ejercicio 2\ndef inverso(x: int) -> int:\n    return int(str(x)[::-1])\n\n# Soluci\u00f3n del ejercicio 3\ndef siguiente(x: int) -> int:\n    return x + inverso(x)\n\n# Soluci\u00f3n del ejercicio 4\ndef busquedaDeCapicua(x: int) -> list[int]:\n    if esCapicua(x):\n        return [x]\n    return [x] + busquedaDeCapicua(siguiente(x))\n\n# Soluci\u00f3n del ejercicio 5\ndef capicuaFinal(x: int) -> int:\n    return busquedaDeCapicua(x)[-1]\n\n# Soluci\u00f3n del ejercicio 6\ndef orden(x: int) -> int:\n    if esCapicua(x):\n        return 0\n    return 1 + orden(siguiente(x))\n\n# Soluci\u00f3n del ejercicio 7\ndef ordenMayor(x: int, n: int) -> bool:\n    if esCapicua(x):\n        return n == 0\n    if n <= 0:\n        return True\n    return ordenMayor(siguiente(x), n - 1)\n\n# Soluci\u00f3n del ejercicio 8\n# ========================\n\n# naturales es el generador de los n\u00fameros naturales positivos, Por\n# ejemplo,\n#    >>> list(islice(naturales(), 5))\n#    [1, 2, 3, 4, 5]\ndef naturales() -> Iterator[int]:\n    i = 1\n    while True:\n        yield i\n        i += 1\n\ndef ordenEntre(m: int, n: int) -> Generator[int, None, None]:\n    return (x for x in naturales()\n            if ordenMayor(x, m) and not ordenMayor(x, n))\n\n# Soluci\u00f3n del ejercicio 9\ndef menorDeOrdenMayor(n: int) -> int:\n    return list(islice((x for x in naturales() if ordenMayor(x, n)), 1))[0]\n\n# Soluci\u00f3n del ejercicio 10\ndef menoresdDeOrdenMayor(m: int) -> list[tuple[int, int]]:\n    return [(n, menorDeOrdenMayor(n)) for n in range(1, m + 1)]\n\n# Soluci\u00f3n del ejercicio 11\n# La conjetura es que para n mayor que 1, la \u00faltima cifra de\n# menorDeOrdenMayor(n) es 9.\n\n# Soluci\u00f3n del ejercicio 12\n# =========================\n\n# La conjetura es\n# @given(st.integers(min_value=2, max_value=200))\n# def test_menorDeOrdenMayor(n: int) -> None:\n#     assert menorDeOrdenMayor(n) % 10 == 9\n\n# La comprobaci\u00f3n es\n#    src> poetry run pytest -q numeros_de_Lychrel.py\n#    E       assert (196 % 10) == 9\n#    E        +  where 196 = menorDeOrdenMayor(25)\n#    E       Falsifying example: test_menorDeOrdenMayor(\n#    E           n=25,\n#    E       )\n\n# Se puede comprobar que 25 es un contraejemplo,\n#    >>> menorDeOrdenMayor(25)\n#    196\n\n# Soluci\u00f3n del ejercicio 13\n# El c\u00e1lculo es\n#    \u03bb> menoresdDeOrdenMayor 50\n#    [(1,10),(2,19),(3,59),(4,69),(5,79),(6,79),(7,89),(8,89),(9,89),\n#     (10,89),(11,89),(12,89),(13,89),(14,89),(15,89),(16,89),(17,89),\n#     (18,89),(19,89),(20,89),(21,89),(22,89),(23,89),(24,89),(25,196),\n#     (26,196),(27,196),(28,196),(29,196),(30,196),(31,196),(32,196),\n#     (33,196),(34,196),(35,196),(36,196),(37,196),(38,196),(39,196),\n#     (40,196),(41,196),(42,196),(43,196),(44,196),(45,196),(46,196),\n#     (47,196),(48,196),(49,196),(50,196)]\n\n# Soluci\u00f3n del ejercicio 14\n# El orden de 196 es infinito y, por tanto, 196 es un n\u00famero\n# de Lychrel.\n\n\n# Soluci\u00f3n del ejercicio 15\n# =========================\n\n# La propiedad es\n@settings(deadline=None)\n@given(st.integers(min_value=2, max_value=5000))\ndef test_ordenDe196(n: int) -> None:\n    assert ordenMayor(196, n)\n\n# La comprobaci\u00f3n es\n#    src> poetry run pytest -q numeros_de_Lychrel.py\n#    1 passed in 7.74s\n<\/pre>\n<p><a name=\"ej2\"><\/a><\/p>\n<h3>2. Suma de los d\u00edgitos de una cadena<\/h3>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   sumaDigitos :: String -> Int\n<\/pre>\n<p>tal que <code>sumaDigitos xs<\/code> es la suma de los d\u00edgitos de la cadena <code>xs<\/code>. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   sumaDigitos \"SE 2431 X\"  ==  10\n<\/pre>\n<p><b>2.1. Soluciones en Haskell<\/b><\/p>\n<pre lang=\"haskell\">\nimport Data.Char (digitToInt, isDigit)\nimport Test.QuickCheck\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\nsumaDigitos1 :: String -> Int\nsumaDigitos1 xs = sum [digitToInt x | x <- xs, isDigit x]\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\nsumaDigitos2 :: String -> Int\nsumaDigitos2 [] = 0\nsumaDigitos2 (x:xs)\n  | isDigit x  = digitToInt x + sumaDigitos2 xs\n  | otherwise  = sumaDigitos2 xs\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\nsumaDigitos3 :: String -> Int\nsumaDigitos3 xs = sum (map digitToInt (filter isDigit xs))\n\n-- 4\u00aa soluci\u00f3n\n-- ===========\n\nsumaDigitos4 :: String -> Int\nsumaDigitos4 = sum . map digitToInt . filter isDigit\n\n-- Comprobaci\u00f3n de equivalencia\n-- ============================\n\n-- La propiedad es\nprop_sumaDigitos :: String -> Bool\nprop_sumaDigitos xs =\n  all (== sumaDigitos1 xs)\n      [sumaDigitos2 xs,\n       sumaDigitos3 xs,\n       sumaDigitos4 xs]\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheck prop_sumaDigitos\n--    +++ OK, passed 100 tests.\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- La comparaci\u00f3n es\n--    \u03bb> sumaDigitos1 (take (4*10^6) (cycle \"ab12\"))\n--    3000000\n--    (1.92 secs, 819,045,328 bytes)\n--    \u03bb> sumaDigitos2 (take (4*10^6) (cycle \"ab12\"))\n--    3000000\n--    (1.79 secs, 856,419,112 bytes)\n--    \u03bb> sumaDigitos3 (take (4*10^6) (cycle \"ab12\"))\n--    3000000\n--    (0.62 secs, 723,045,296 bytes)\n--    \u03bb> sumaDigitos4 (take (4*10^6) (cycle \"ab12\"))\n--    3000000\n--    (0.63 secs, 723,045,552 bytes)\n<\/pre>\n<p><b>2.2. Soluciones en Python<\/b><\/p>\n<pre lang=\"python\">\nfrom sys import setrecursionlimit\nfrom timeit import Timer, default_timer\n\nfrom hypothesis import given\nfrom hypothesis import strategies as st\n\nsetrecursionlimit(10**6)\n\n# 1\u00aa soluci\u00f3n\n# ===========\n\ndef sumaDigitos1(xs: str) -> int:\n    return sum((int(x) for x in xs if x.isdigit()))\n\n# 2\u00aa soluci\u00f3n\n# ===========\n\ndef sumaDigitos2(xs: str) -> int:\n    if xs:\n        if xs[0].isdigit():\n            return int(xs[0]) + sumaDigitos2(xs[1:])\n        return sumaDigitos2(xs[1:])\n    return 0\n\n# 3\u00aa soluci\u00f3n\n# ===========\n\ndef sumaDigitos3(xs: str) -> int:\n    r = 0\n    for x in xs:\n        if x.isdigit():\n            r = r + int(x)\n    return r\n\n# Comprobaci\u00f3n de equivalencia\n# ============================\n\n# La propiedad es\n@given(st.text())\ndef test_sumaDigitos(xs: str) -> None:\n    r = sumaDigitos1(xs)\n    assert sumaDigitos2(xs) == r\n    assert sumaDigitos3(xs) == r\n\n# La comprobaci\u00f3n es\n#    src> poetry run pytest -q suma_de_digitos_de_cadena.py\n#    1 passed in 0.41s\n\n# Comparaci\u00f3n de eficiencia\n# =========================\n\ndef tiempo(e: str) -> None:\n    \"\"\"Tiempo (en segundos) de evaluar la expresi\u00f3n e.\"\"\"\n    t = Timer(e, \"\", default_timer, globals()).timeit(1)\n    print(f\"{t:0.2f} segundos\")\n\n# La comparaci\u00f3n es\n#    >>> tiempo('mayorExponente1(2, 2**(2*10**4))')\n\n\n# Comparaci\u00f3n de eficiencia\n# =========================\n#\n# La comparaci\u00f3n es\n#    >>> tiempo('sumaDigitos1(\"ab12\"*5000)')\n#    0.00 segundos\n#    >>> tiempo('sumaDigitos2(\"ab12\"*5000)')\n#    0.02 segundos\n#    >>> tiempo('sumaDigitos3(\"ab12\"*5000)')\n#    0.00 segundos\n#\n#    >>> tiempo('sumaDigitos1(\"ab12\"*(5*10**6))')\n#    1.60 segundos\n#    >>> tiempo('sumaDigitos3(\"ab12\"*(5*10**6))')\n#    1.83 segundos\n<\/pre>\n<p><a name=\"ej3\"><\/a><\/p>\n<h3>3. Poner en may\u00fascula la primera letra y las restantes en min\u00fasculas<\/h3>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   mayusculaInicial :: String -> String\n<\/pre>\n<p>tal que <code>mayusculaInicial xs<\/code> es la palabra <code>xs<\/code> con la letra inicial en may\u00fascula y las restantes en min\u00fasculas. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   mayusculaInicial \"sEviLLa\"  ==  \"Sevilla\"\n   mayusculaInicial \"\"         ==  \"\"\n<\/pre>\n<p><b>3.1. Soluciones en Haskell<\/b><\/p>\n<pre lang=\"haskell\">\nimport Data.Char (toUpper, toLower)\nimport Test.QuickCheck\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\nmayusculaInicial1 :: String -> String\nmayusculaInicial1 []     = []\nmayusculaInicial1 (x:xs) = toUpper x : [toLower y | y <- xs]\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\nmayusculaInicial2 :: String -> String\nmayusculaInicial2 [] = []\nmayusculaInicial2 (x:xs) = toUpper x : aux xs\n  where aux (y:ys) = toLower y : aux ys\n        aux []     = []\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\nmayusculaInicial3 :: String -> String\nmayusculaInicial3 [] = []\nmayusculaInicial3 (x:xs) = toUpper x : map toLower xs\n\n-- Comprobaci\u00f3n de equivalencia\n-- ============================\n\n-- La propiedad es\nprop_mayusculaInicial :: String -> Bool\nprop_mayusculaInicial xs =\n  all (== mayusculaInicial1 xs)\n      [mayusculaInicial2 xs,\n       mayusculaInicial3 xs]\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheck prop_mayusculaInicial\n--    +++ OK, passed 100 tests.\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- La comparaci\u00f3n es\n--    \u03bb> length (mayusculaInicial1 (take (10^7) (cycle \"aA\")))\n--    10000000\n--    (2.22 secs, 1,680,592,240 bytes)\n--    \u03bb> length (mayusculaInicial2 (take (10^7) (cycle \"aA\")))\n--    10000000\n--    (2.57 secs, 2,240,592,192 bytes)\n--    \u03bb> length (mayusculaInicial3 (take (10^7) (cycle \"aA\")))\n--    10000000\n--    (0.16 secs, 1,440,592,192 bytes)\n<\/pre>\n<p><b>3.2. Soluciones en Python<\/b><\/p>\n<pre lang=\"python\">\nfrom sys import setrecursionlimit\nfrom timeit import Timer, default_timer\n\nfrom hypothesis import given\nfrom hypothesis import strategies as st\n\nsetrecursionlimit(10**6)\n\n# 1\u00aa soluci\u00f3n\n# ===========\n\ndef mayusculaInicial1(xs: str) -> str:\n    if xs:\n        return \"\".join([xs[0].upper()] + [y.lower() for y in xs[1:]])\n    return \"\"\n\n# 2\u00aa soluci\u00f3n\n# ===========\n\ndef mayusculaInicial2(xs: str) -> str:\n    def aux(ys: str) -> str:\n        if ys:\n            return ys[0].lower() + aux(ys[1:])\n        return \"\"\n    if xs:\n        return \"\".join(xs[0].upper() + aux(xs[1:]))\n    return \"\"\n\n# 3\u00aa soluci\u00f3n\n# ===========\n\ndef mayusculaInicial3(xs: str) -> str:\n    if xs:\n        return \"\".join([xs[0].upper()] + list(map(str.lower, xs[1:])))\n    return \"\"\n\n# 4\u00aa soluci\u00f3n\n# ===========\n\ndef mayusculaInicial4(xs: str) -> str:\n    return xs.capitalize()\n\n# Comprobaci\u00f3n de equivalencia\n# ============================\n\n# La propiedad es\n@given(st.text())\ndef test_mayusculaInicial(xs: str) -> None:\n    r = mayusculaInicial1(xs)\n    assert mayusculaInicial2(xs) == r\n    assert mayusculaInicial3(xs) == r\n\n# La comprobaci\u00f3n es\n#    src> poetry run pytest -q mayuscula_inicial.py\n#    1 passed in 0.26s\n\n# Comparaci\u00f3n de eficiencia\n# =========================\n\ndef tiempo(e: str) -> None:\n    \"\"\"Tiempo (en segundos) de evaluar la expresi\u00f3n e.\"\"\"\n    t = Timer(e, \"\", default_timer, globals()).timeit(1)\n    print(f\"{t:0.2f} segundos\")\n\n# La comparaci\u00f3n es\n#    >>> tiempo('len(mayusculaInicial1(\"aB\"*(10**7)))')\n#    1.92 segundos\n#    >>> tiempo('len(mayusculaInicial2(\"aB\"*(10**7)))')\n#    Process Python terminado (killed)\n#    >>> tiempo('len(mayusculaInicial3(\"aB\"*(10**7)))')\n#    1.59 segundos\n#    >>> tiempo('len(mayusculaInicial4(\"aB\"*(10**7)))')\n#    0.13 segundos\n<\/pre>\n<p><a name=\"ej4\"><\/a><\/p>\n<h3>4. May\u00fasculas iniciales<\/h3>\n<p>Se consideran las siguientes reglas de may\u00fasculas iniciales para los t\u00edtulos:<\/p>\n<ul>\n<li>la primera palabra comienza en may\u00fascula y<\/li>\n<li>todas las palabras que tienen 4 letras como m\u00ednimo empiezan con may\u00fasculas<\/li>\n<\/ul>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   titulo :: [String] -> [String]\n<\/pre>\n<p>tal que <code>titulo ps<\/code> es la lista de las palabras de <code>ps<\/code> con las reglas de may\u00fasculas iniciales de los t\u00edtulos. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   \u03bb> titulo [\"eL\",\"arTE\",\"DE\",\"La\",\"proGraMacion<\/b>\n   [\"El\",\"Arte\",\"de\",\"la\",\"Programacion<\/b>\n<\/pre>\n<p><b>4.1. Soluciones en Haskell<\/b><\/p>\n<pre lang=\"haskell\">\nimport Data.Char (toUpper, toLower)\nimport Test.QuickCheck\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\ntitulo1 :: [String] -> [String]\ntitulo1 []     = []\ntitulo1 (p:ps) = mayusculaInicial p : [transforma q | q <- ps]\n\n-- (mayusculaInicial xs) es la palabra xs con la letra inicial\n-- en may\u00fascula y las restantes en min\u00fasculas. Por ejemplo,\n--    mayusculaInicial \"sEviLLa\"  ==  \"Sevilla\"\nmayusculaInicial :: String -> String\nmayusculaInicial []     = []\nmayusculaInicial (x:xs) = toUpper x : [toLower y | y <- xs]\n\n-- (transforma p) es la palabra p con may\u00fascula inicial si su longitud\n-- es mayor o igual que 4 y es p en min\u00fascula en caso contrario\ntransforma :: String -> String\ntransforma p | length p >= 4 = mayusculaInicial p\n             | otherwise     = minuscula p\n\n-- (minuscula xs) es la palabra xs en min\u00fascula.\nminuscula :: String -> String\nminuscula xs = [toLower x | x <- xs]\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\ntitulo2 :: [String] -> [String]\ntitulo2 []     = []\ntitulo2 (p:ps) = mayusculaInicial p : aux ps\n  where aux []     = []\n        aux (q:qs) = transforma q : aux qs\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\ntitulo3 :: [String] -> [String]\ntitulo3 []     = []\ntitulo3 (p:ps) = mayusculaInicial p : map transforma ps\n\n-- Comprobaci\u00f3n de equivalencia\n-- ============================\n\n-- La propiedad es\nprop_titulo :: [String] -> Bool\nprop_titulo xs =\n  all (== titulo1 xs)\n      [titulo2 xs,\n       titulo3 xs]\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheck prop_titulo\n--    +++ OK, passed 100 tests.\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- La comparaci\u00f3n es\n--    \u03bb> length (titulo1 (take (10^7) (cycle [\"hOy\",\"Es\",\"juEves\",\"dE\",\"Noviembre<\/b>)))\n--    10000000\n--    (2.17 secs, 1,680,592,512 bytes)\n--    \u03bb> length (titulo2 (take (10^7) (cycle [\"hOy\",\"Es\",\"juEves\",\"dE\",\"Noviembre<\/b>)))\n--    10000000\n--    (2.45 secs, 2,240,592,464 bytes)\n--    \u03bb> length (titulo3 (take (10^7) (cycle [\"hOy\",\"Es\",\"juEves\",\"dE\",\"Noviembre<\/b>)))\n--    10000000\n--    (0.16 secs, 1,440,592,464 bytes)\n<\/pre>\n<p><b>4.2. Soluciones en Python<\/b><\/p>\n<pre lang=\"python\">\nfrom sys import setrecursionlimit\nfrom timeit import Timer, default_timer\n\nfrom hypothesis import given\nfrom hypothesis import strategies as st\n\nsetrecursionlimit(10**6)\n\n# 1\u00aa soluci\u00f3n\n# ===========\n\n# (mayusculaInicial xs) es la palabra xs con la letra inicial\n# en may\u00fascula y las restantes en min\u00fasculas. Por ejemplo,\n#    mayusculaInicial(\"sEviLLa\")  ==  \"Sevilla\"\ndef mayusculaInicial(xs: str) -> str:\n    return xs.capitalize()\n\n# (minuscula xs) es la palabra xs en min\u00fascula.\ndef minuscula(xs: str) -> str:\n    return xs.lower()\n\n# (transforma p) es la palabra p con may\u00fascula inicial si su longitud\n# es mayor o igual que 4 y es p en min\u00fascula en caso contrario\ndef transforma(p: str) -> str:\n    if len(p) >= 4:\n        return mayusculaInicial(p)\n    return minuscula(p)\n\ndef titulo1(ps: list[str]) -> list[str]:\n    if ps:\n        return [mayusculaInicial(ps[0])] + [transforma(q) for q in ps[1:]]\n    return []\n\n# 2\u00aa soluci\u00f3n\n# ===========\n\ndef titulo2(ps: list[str]) -> list[str]:\n    def aux(qs: list[str]) -> list[str]:\n        if qs:\n            return [transforma(qs[0])] + aux(qs[1:])\n        return []\n    if ps:\n        return [mayusculaInicial(ps[0])] + aux(ps[1:])\n    return []\n\n# 3\u00aa soluci\u00f3n\n# ===========\n\ndef titulo3(ps: list[str]) -> list[str]:\n    if ps:\n        return [mayusculaInicial(ps[0])] + list(map(transforma, ps[1:]))\n    return []\n\n# Comprobaci\u00f3n de equivalencia\n# ============================\n\n# La propiedad es\n@given(st.lists(st.text()))\ndef test_titulo(ps: list[str]) -> None:\n    r = titulo1(ps)\n    assert titulo2(ps) == r\n    assert titulo3(ps) == r\n\n# La comprobaci\u00f3n es\n#    src> poetry run pytest -q mayusculas_iniciales.py\n#    1 passed in 0.55s\n\n# Comparaci\u00f3n de eficiencia\n# =========================\n\ndef tiempo(e: str) -> None:\n    \"\"\"Tiempo (en segundos) de evaluar la expresi\u00f3n e.\"\"\"\n    t = Timer(e, \"\", default_timer, globals()).timeit(1)\n    print(f\"{t:0.2f} segundos\")\n\n# La comparaci\u00f3n es\n#    >>> tiempo('len(mayusculaInicial1(\"aB\"*(10**7)))')\n#    >>> tiempo('titulo1([\"eL\",\"arTE\",\"DE\",\"La\",\"proGraMacion <\/b>*1900)')\n#    0.00 segundos\n#    >>> tiempo('titulo2([\"eL\",\"arTE\",\"DE\",\"La\",\"proGraMacion <\/b>*1900)')\n#    0.30 segundos\n#    >>> tiempo('titulo3([\"eL\",\"arTE\",\"DE\",\"La\",\"proGraMacion <\/b>*1900)')\n#    0.00 segundos\n#\n#    >>> tiempo('titulo1([\"eL\",\"arTE\",\"DE\",\"La\",\"proGraMacion <\/b>*(2*10**6))')\n#    2.93 segundos\n#    >>> tiempo('titulo3([\"eL\",\"arTE\",\"DE\",\"La\",\"proGraMacion <\/b>*(2*10**6))')\n#    2.35 segundos\n<\/pre>\n<p><a name=\"ej5\"><\/a><\/p>\n<h3>5. Posiciones de un car\u00e1cter en una cadena<\/h3>\n<p>Definir la funci\u00f3n<\/p>\n<pre lang=\"text\">\n   posiciones :: Char -> String -> [Int]\n<\/pre>\n<p>tal que <code>posiciones x ys<\/code> es la lista de la posiciones del car\u00e1cter <code>x<\/code> en la cadena <code>ys<\/code>. Por ejemplo,<\/p>\n<pre lang=\"text\">\n   posiciones 'a' \"Salamamca\"   ==  [1,3,5,8]\n<\/pre>\n<p><b>5.1. Soluciones en Haskell<\/b><\/p>\n<pre lang=\"haskell\">\nimport Data.List (elemIndices)\nimport Test.QuickCheck\n\n-- 1\u00aa soluci\u00f3n\n-- ===========\n\nposiciones1 :: Char -> String -> [Int]\nposiciones1 x ys = [n | (y,n) <- zip ys [0..], y == x]\n\n-- 2\u00aa soluci\u00f3n\n-- ===========\n\nposiciones2 :: Char -> String -> [Int]\nposiciones2 x ys = aux x ys 0\n  where\n    aux _ [] _ = []\n    aux b (a:as) n | a == b    = n : aux b as (n+1)\n                   | otherwise = aux b as (n+1)\n\n-- 3\u00aa soluci\u00f3n\n-- ===========\n\nposiciones3 :: Char -> String -> [Int]\nposiciones3 = elemIndices\n\n-- Comprobaci\u00f3n de equivalencia\n-- ============================\n\n-- La propiedad es\nprop_posiciones :: Char -> String -> Bool\nprop_posiciones x ys =\n  all (== posiciones1 x ys)\n      [posiciones2 x ys,\n       posiciones3 x ys]\n\n-- La comprobaci\u00f3n es\n--    \u03bb> quickCheck prop_posiciones\n--    +++ OK, passed 100 tests.\n\n-- Comparaci\u00f3n de eficiencia\n-- =========================\n\n-- La comparaci\u00f3n es\n--    \u03bb> length (posiciones1 'a' (take (6*10^6) (cycle \"abc\")))\n--    2000000\n--    (2.48 secs, 1,680,591,672 bytes)\n--    \u03bb> length (posiciones2 'a' (take (6*10^6) (cycle \"abc\")))\n--    2000000\n--    (2.98 secs, 1,584,591,720 bytes)\n--    \u03bb> length (posiciones3 'a' (take (6*10^6) (cycle \"abc\")))\n--    2000000\n--    (0.11 secs, 496,591,600 bytes)\n<\/pre>\n<p><b>5.2. Soluciones en Python<\/b><\/p>\n<pre lang=\"python\">\nfrom sys import setrecursionlimit\nfrom timeit import Timer, default_timer\n\nfrom hypothesis import given\nfrom hypothesis import strategies as st\n\nsetrecursionlimit(10**6)\n\n# -- 1\u00aa soluci\u00f3n\n# -- ===========\n\ndef posiciones1(x: str, ys: str) -> list[int]:\n    return [n for (n, y) in enumerate(ys) if y == x]\n\n# -- 2\u00aa soluci\u00f3n\n# -- ===========\n\ndef posiciones2(x: str, ys: str) -> list[int]:\n    def aux(a: str, bs: str, n: int) -> list[int]:\n        if bs:\n            if a == bs[0]:\n                return [n] + aux(a, bs[1:], n + 1)\n            return aux(a, bs[1:], n + 1)\n        return []\n    return aux(x, ys, 0)\n\n# -- 3\u00aa soluci\u00f3n\n# -- ===========\n\ndef posiciones3(x: str, ys: str) -> list[int]:\n    r = []\n    for n, y in enumerate(ys):\n        if x == y:\n            r.append(n)\n    return r\n\n# La propiedad es\n@given(st.text(), st.text())\ndef test_posiciones(x: str, ys: str) -> None:\n    r = posiciones1(x, ys)\n    assert posiciones2(x, ys) == r\n    assert posiciones3(x, ys) == r\n\n# La comprobaci\u00f3n es\n#    src> poetry run pytest -q posiciones_de_un_caracter_en_una_cadena.py\n#    1 passed in 0.29s\n\n# Comparaci\u00f3n de eficiencia\n# =========================\n\ndef tiempo(e: str) -> None:\n    \"\"\"Tiempo (en segundos) de evaluar la expresi\u00f3n e.\"\"\"\n    t = Timer(e, \"\", default_timer, globals()).timeit(1)\n    print(f\"{t:0.2f} segundos\")\n\n# La comparaci\u00f3n es\n#    >>> tiempo('posiciones1(\"a\", \"abc\"*6000)')\n#    0.00 segundos\n#    >>> tiempo('posiciones2(\"a\", \"abc\"*6000)')\n#    0.06 segundos\n#    >>> tiempo('posiciones3(\"a\", \"abc\"*6000)')\n#    0.00 segundos\n#\n#    >>> tiempo('posiciones1(\"a\", \"abc\"*(2*10**7))')\n#    3.02 segundos\n#    >>> tiempo('posiciones3(\"a\", \"abc\"*(2*10**7))')\n#    3.47 segundos\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Esta semana he publicado en Exercitium las soluciones de los siguientes problemas: 1. N\u00fameros de Lychrel 2. Suma de los d\u00edgitos de una cadena 3. Poner en may\u00fascula la primera letra y las restantes en min\u00fasculas 4. May\u00fasculas iniciales 5. Posiciones de un car\u00e1cter en una cadena A continuaci\u00f3n se muestran las soluciones.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"footnotes":"","_jetpack_memberships_contains_paid_content":false},"categories":[337],"tags":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_likes_enabled":false,"_links":{"self":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/7840"}],"collection":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/comments?post=7840"}],"version-history":[{"count":1,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/7840\/revisions"}],"predecessor-version":[{"id":7841,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/posts\/7840\/revisions\/7841"}],"wp:attachment":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/media?parent=7840"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/categories?post=7840"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/vestigium\/wp-json\/wp\/v2\/tags?post=7840"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}