{"id":7497,"date":"2022-11-04T06:00:10","date_gmt":"2022-11-04T04:00:10","guid":{"rendered":"http:\/\/www.glc.us.es\/~jalonso\/exercitium\/?p=7497"},"modified":"2022-12-14T12:15:18","modified_gmt":"2022-12-14T10:15:18","slug":"el-algoritmo-de-luhn","status":"publish","type":"post","link":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/el-algoritmo-de-luhn\/","title":{"rendered":"El algoritmo de Luhn"},"content":{"rendered":"<p>El objetivo de este ejercicio es estudiar un algoritmo para validar algunos identificadores num\u00e9ricos como los n\u00fameros de algunas tarjetas de cr\u00e9dito; por ejemplo, las de tipo Visa o Master Card.<\/p>\n<p>El algoritmo que vamos a estudiar es el <a href=\"https:\/\/bit.ly\/3DX1llv\">algoritmo de Luhn<\/a> consistente en aplicar los siguientes pasos a los d\u00edgitos del n\u00famero de la tarjeta.<\/p>\n<ol>\n<li>Se invierten los d\u00edgitos del n\u00famero; por ejemplo, [9,4,5,5] se transforma en [5,5,4,9].<\/li>\n<li>Se duplican los d\u00edgitos que se encuentra en posiciones impares (empezando a contar en 0); por ejemplo, [5,5,4,9] se transforma en [5,10,4,18].<\/li>\n<li>Se suman los d\u00edgitos de cada n\u00famero; por ejemplo, [5,10,4,18] se transforma en 5 + (1 + 0) + 4 + (1 + 8) = 19.<\/li>\n<li>Si el \u00faltimo d\u00edgito de la suma es 0, el n\u00famero es v\u00e1lido; y no lo es, en caso contrario.<\/li>\n<\/ol>\n<p>A los n\u00fameros v\u00e1lidos, se les llama n\u00fameros de Luhn.<\/p>\n<p>Definir las siguientes funciones:<\/p>\n<pre lang=\"text\">\n   digitosInv    :: Integer -> [Integer]\n   doblePosImpar :: [Integer] -> [Integer]\n   sumaDigitos   :: [Integer] -> Integer\n   ultimoDigito  :: Integer -> Integer\n   luhn          :: Integer -> Bool\n<\/pre>\n<p>tales que<\/p>\n<ul>\n<li><code>digitosInv n<\/code> es la lista de los d\u00edgitos del n\u00famero <code>n<\/code>, en orden inverso. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     digitosInv 320274  ==  [4,7,2,0,2,3]\n<\/pre>\n<ul>\n<li><code>doblePosImpar ns<\/code> es la lista obtenida doblando los elementos de <code>ns<\/code> en las posiciones impares (empezando a contar en cero y dejando igual a los que est\u00e1n en posiciones pares. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     doblePosImpar [4,9,5,5]    ==  [4,18,5,10]\n     doblePosImpar [4,9,5,5,7]  ==  [4,18,5,10,7]\n<\/pre>\n<ul>\n<li><code>sumaDigitos ns<\/code> es la suma de los d\u00edgitos de <code>ns<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     sumaDigitos [10,5,18,4] = 1 + 0 + 5 + 1 + 8 + 4 =\n                             = 19\n<\/pre>\n<ul>\n<li><code>ultimoDigito n<\/code> es el \u00faltimo d\u00edgito de <code>n<\/code>. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     ultimoDigito 123 == 3\n     ultimoDigito   0 == 0\n<\/pre>\n<ul>\n<li><code>luhn n<\/code> se verifica si <code>n<\/code> es un n\u00famero de Luhn. Por ejemplo,<\/li>\n<\/ul>\n<pre lang=\"text\">\n     luhn 5594589764218858  ==  True\n     luhn 1234567898765432  ==  False\n<\/pre>\n<p><b>Soluciones<\/b><\/p>\n<p>A continuaci\u00f3n se muestran las <a href=\"#haskell\">soluciones en Haskell<\/a> y las <a href=\"#python\">soluciones en Python<\/a>.<\/p>\n<p><a name=\"haskell\"><\/a><br \/>\n<b>Soluciones en Haskell<\/b><\/p>\n<pre lang=\"haskell\">\n-- Definici\u00f3n de digitosInv\n-- ========================\n\ndigitosInv :: Integer -> [Integer]\ndigitosInv n = [read [x] | x <- reverse (show n)]\n\n-- Nota: En el ejercicio \"D\u00edgitos de un n\u00famero\" https:\/\/bit.ly\/3Tkhc2T\n-- se presentan otras definiciones.\n\n-- Definiciones de doblePosImpar\n-- =============================\n\n-- 1\u00aa definici\u00f3n\ndoblePosImpar :: [Integer] -> [Integer]\ndoblePosImpar []       = []\ndoblePosImpar [x]      = [x]\ndoblePosImpar (x:y:zs) = x : 2*y : doblePosImpar zs\n\n-- 2\u00aa definici\u00f3n\ndoblePosImpar2 :: [Integer] -> [Integer]\ndoblePosImpar2 (x:y:zs) = x : 2*y : doblePosImpar2 zs\ndoblePosImpar2 xs       = xs\n\n-- 3\u00aa definici\u00f3n\ndoblePosImpar3 :: [Integer] -> [Integer]\ndoblePosImpar3 xs = [f n x | (n,x) <- zip [0..] xs]\n  where f n x | odd n     = 2*x\n              | otherwise = x\n\n-- Definiciones de sumaDigitos\n-- ===========================\n\nsumaDigitos :: [Integer] -> Integer\nsumaDigitos ns = sum [sum (digitosInv n) | n <- ns]\n\n-- Nota: En el ejercicio \"Suma de los d\u00edgitos de un n\u00famero\"\n-- https:\/\/bit.ly\/3U4u7WR se presentan otras definiciones.\n\n-- Definici\u00f3n de ultimoDigito\n-- ==========================\n\nultimoDigito :: Integer -> Integer\nultimoDigito n = n `rem` 10\n\n-- Definiciones de luhn\n-- ====================\n\n-- 1\u00aa definici\u00f3n\nluhn1 :: Integer -> Bool\nluhn1 n =\n  ultimoDigito (sumaDigitos (doblePosImpar (digitosInv n))) == 0\n\n-- 2\u00aa definici\u00f3n\nluhn2 :: Integer -> Bool\nluhn2 =\n  (==0) . ultimoDigito . sumaDigitos . doblePosImpar . digitosInv\n<\/pre>\n<p><a name=\"python\"><\/a><br \/>\n<b>Soluciones en Python<\/b><\/p>\n<pre lang=\"python\">\n# Definici\u00f3n de digitosInv\n# ========================\n\ndef digitosInv(n: int) -> list[int]:\n    return [int(x) for x in reversed(str(n))]\n\n# Nota: En el ejercicio \"D\u00edgitos de un n\u00famero\" https:\/\/bit.ly\/3Tkhc2T\n# se presentan otras definiciones.\n\n# Definiciones de doblePosImpar\n# =============================\n\n# 1\u00aa definici\u00f3n\ndef doblePosImpar(xs: list[int]) -> list[int]:\n    if len(xs) <= 1:\n        return xs\n    return [xs[0]] + [2*xs[1]] + doblePosImpar(xs[2:])\n\n# 2\u00aa definici\u00f3n\ndef doblePosImpar2(xs: list[int]) -> list[int]:\n    def f(n: int, x: int) -> int:\n        if n % 2 == 1:\n            return 2 * x\n        return x\n    return [f(n, x) for (n, x) in enumerate(xs)]\n\n# Definiciones de sumaDigitos\n# ===========================\n\ndef sumaDigitos(ns: list[int]) -> int:\n    return sum((sum(digitosInv(n)) for n in ns))\n\n# Nota: En el ejercicio \"Suma de los d\u00edgitos de un n\u00famero\"\n# https:\/\/bit.ly\/3U4u7WR se presentan otras definiciones.\n\n# Definici\u00f3n de ultimoDigito\n# ==========================\n\ndef ultimoDigito(n: int) -> int:\n    return n % 10\n\n# Definiciones de luhn\n# ====================\n\ndef luhn(n: int) -> bool:\n    return ultimoDigito(sumaDigitos(doblePosImpar(digitosInv(n)))) == 0\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>El objetivo de este ejercicio es estudiar un algoritmo para validar algunos identificadores num\u00e9ricos como los n\u00fameros de algunas tarjetas de cr\u00e9dito; por ejemplo, las de tipo Visa o Master Card. El algoritmo que vamos a estudiar es el algoritmo de Luhn consistente en aplicar los siguientes pasos a los d\u00edgitos del n\u00famero de la&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","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":[581],"tags":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/7497"}],"collection":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/comments?post=7497"}],"version-history":[{"count":2,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/7497\/revisions"}],"predecessor-version":[{"id":7655,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/posts\/7497\/revisions\/7655"}],"wp:attachment":[{"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/media?parent=7497"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/categories?post=7497"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.glc.us.es\/~jalonso\/exercitium\/wp-json\/wp\/v2\/tags?post=7497"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}