O algoritmo Luhn para verificar números de cartão de crédito, etc.


50

Desafio

Escreva o programa ou a função mais curta para calcular o algoritmo Luhn para verificar os números (cartão de crédito).

Algoritmo de Luhn explicado

No RosettaCode , esse algoritmo para os objetivos deste desafio é especificado como tal, com a entrada de exemplo de 49927398716:

Reverse the digits, make an array:
    6, 1, 7, 8, 9, 3, 7, 2, 9, 9, 4
Double the numbers in odd indexes:
    6, 2, 7, 16, 9, 6, 7, 4, 9, 18, 4
Sum the digits in each number:
    6, 2, 7, 7, 9, 6, 7, 4, 9, 9, 4
Sum all of the numbers:
    6 + 2 + 7 + 7 + 9 + 6 + 7 + 4 + 9 + 9 + 4 = 70
If the sum modulo 10 is 0, then the number is valid:
    70 % 10 = 0 => valid

Regras de IO

Entrada : uma sequência ou número (sua escolha), no formato de entrada / saída de seu idioma preferido

Saída : Um valor verdadeiro ou falso , respectivamente, indicando se a entrada é válida ou não, de acordo com o teste acima.

Notas / Dicas

  • Tente não lançar acidentalmente seu próprio cartão de crédito ou números de conta, se você os usar para testar :)

  • Se a entrada for inválida e impossível de processar com o algoritmo especificado (ou seja, muito curto para trabalhar), você poderá fazer o que quiser, incluindo desligar meu computador.

  • No entanto , o marcador anterior não significa que seu idioma possa fazer o que quiser com números grandes demais para serem manipulados. Se seu idioma não for capaz de lidar com um caso de teste, considere usar uma string como entrada.

Exemplos

Os exemplos a seguir foram validados com este script Python ; se você acha que alguém está errado ou tem uma pergunta, basta executar ping @cat.

49927398716      True
49927398717      False
1234567812345670 True    
1234567812345678 False
79927398710      False
79927398711      False
79927398712      False
79927398713      True
79927398714      False
79927398715      False
79927398716      False
79927398717      False
79927398718      False
79927398719      False
374652346956782346957823694857692364857368475368 True
374652346956782346957823694857692364857387456834 False
8 False **
0 True  **

** de acordo com a implementação do Python, mas você pode fazer qualquer coisa, porque estas são muito curtas para serem elegíveis por uma aderência estrita à especificação.


Se qualquer uma das opções acima invalida as respostas existentes (embora eu acredite que isso não seja possível), essas respostas ainda são válidas. No entanto, novas respostas, para serem válidas, devem seguir a especificação acima.

Entre os melhores

Respostas:


21

Golfscript - 24 caracteres

-1%{2+0!:0)*109%+}*10%8=

Explicação:

  1. -1% inverte a string
  2. {inicia um bloco (que usamos como um loop). Cada caractere nas cadeias é pressionado, pois é um valor ASCII.
    1. 2+ adiciona 2. (o valor ascii de um dígito é 48 + n, então temos 50 + n agora e o último dígito é n)
    2. 0!:0 inverte o valor de 0 e o armazena (tudo é uma variável); portanto, temos 1 na primeira iteração, 0 na segunda etc.
    3. )* adiciona um a esse valor e o multiplica, então multiplicamos por 2, depois 1, depois 2 etc.
    4. 109% é o restante módulo 109. Isso afeta apenas os valores 5-9 que foram dobrados e os reduz ao valor correto.
    5. + adiciona esse valor à soma em execução
  3. }*finaliza o bloco e faz uma operação de 'dobra'. Primeiro, o primeiro caractere é pressionado (já que invertemos, esse é o dígito de verificação). Em seguida, pressione e execute o bloco alternadamente. Portanto, estamos usando o valor ascii do primeiro caractere como o valor inicial da soma em execução.
  4. 10% toma o restante módulo 10.
  5. 8= retornará 1 se o valor for 8. Usamos isso porque não normalizamos o primeiro caractere pressionado (o dígito de verificação).

Pode-se pensar que poderíamos usar em 8-vez de 2+salvar um personagem mudando 109%para 89%, exceto que precisaríamos adicionar um espaço para que a -subtração seja (em vez de -0).


11

GolfScript, 44 caracteres

-1%{16%}%2/1,\+{(\.{0=2*.9>9*-+}{;}if+}*10%!

Comentário selecionado

Curiosamente, os dois primeiros itens abaixo demonstram três usos completamente diferentes do %operador: seleção de matriz, mapa e mod. A maioria dos operadores do GolfScript é "sensível ao contexto", oferecendo comportamentos extremamente divergentes, dependendo do tipo de argumento.

  1. -1%inverte a string. Isso é importante, pois os pares de dígitos são contados da direita.
  2. {16%}% converte todos os dígitos ASCII em números, modificando-os com 16.
  3. 2/ divide a matriz em grupos de 2.
  4. 1,é uma maneira barata de fazer [0].
  5. \+acrescenta efetivamente o 0 à matriz de dígitos. Isso é feito trocando e concatenando.

O 0 é anexado em preparação para a dobra que vem a seguir. Em vez de pegar um valor inicial explícito, a dobra do GolfScript usa o primeiro item da matriz como valor inicial.

Agora, vejamos a função de dobra real. Essa função usa dois argumentos: o valor dobrado e o item atual na matriz (que neste caso será uma matriz de 2 ou (incomum) 1, devido ao 2/anterior). Vamos supor que os argumentos sejam 1 [2 3].

  1. (\.divide o elemento da matriz mais à esquerda, move a matriz restante para a frente e depois a copia. Empilhar agora se parece com: 1 2 [3] [3].
  2. Os ifcontrolos se a matriz está vazio (que é o caso para o último grupo quando se lida com um número de conta estranha de tamanho). Nesse caso, não ocorre nenhum processamento especial (apenas saia da matriz vazia).
  3. Para um grupo par:
    1. 0= agarra o primeiro (apenas, neste caso) elemento da matriz. 1 2 3
    2. 2* dobra o número. 1 2 6
    3. .9>9*- subtrai 9 do número se for maior que 9. Implementado como: copie o número, compare com 9, multiplique o resultado (que é 0 ou 1) por 9 e subtraia. 1 2 6
    4. + finalmente adiciona isso ao primeiro número. 1 8
  4. +(depois de if) adiciona o resultado de ifao valor original, resultando no novo valor dobrado.

Depois que a dobra é concluída, simplesmente modificamos com 10 ( 10%) e negamos o resultado ( !), para que retornemos 1 se a soma for um múltiplo de 10.


Isto parece devolver 0 para o número do exemplo em Wikipedia (49927398716)
gnibbler

nm. Eu esqueci de usarecho -n
gnibbler

11
@gnibbler: Haha, falha. :-P (Sério, eu fui picado por aquele também, no meu teste inicial.)
Chris Jester-Young

11
Alguns lugares para salvar alguns caracteres fáceis aqui. -1% 2/pode ser combinado em -2/. 1,pode ser substituído por 0(0 é coagido a uma matriz e +concatenado). 9>9*-pode ser substituído por 9>+(já que estamos preocupados apenas com o último dígito). Além disso, a verificação de comprimentos ímpares é um pouco longa, o uso .,2%,\+é mais curto. Depois de fazer isso, também podemos mudar {16%}%e (\0=em {16}/(dentro do loop). Depois de ter feito tudo isso, ele vai ser algo como isto: .,2%,\+-2/0\+{{16%}/2*.9>+++}*10%!.
Nabb

@Nabb: Obrigado! Vou incorporá-los à minha solução, embora pareça que você já tem uma que está chutando o traseiro sério. :-)
Chris Jester-Young

11

Python, 73 69 caracteres

def P(x):D=map(int,x);return sum(D+[d-d/5*9for d in D[-2::-2]])%10==0

4
Você pode salvar mais dois caracteres por não looping para trás: D[-2::-2]-> D[1::2]como o fim de uma soma não é importante :)
ThinkChaos

==0pode ser reduzido para<1
Black Owl Kai

10

Python 3, 77 bytes

c=lambda a:sum(sum(divmod(int(a[-e-1])<<e%2,10))for e in range(len(a)))%10==0

9

Caracteres C # 119:

bool l(string n){return(String.Join("",n.Reverse().Select((x,i)=>(x-48)*(i%2<1?1:2)+"").ToArray()).Sum(x=>x-48))%10<1;}

Não é tão ruim para um código de golfe n00b em uma linguagem estaticamente tipada, espero.

Isso pode ser reduzido para 100 :

bool l(string n){return String.Join("",n.Reverse().Select((x,i)=>(x-48)*(i%2+1))).Sum(x=>x+2)%10<1;}

É uma boa ideia e uma abordagem interessante, mas não parece funcionar. Pelo menos não com meus poucos testes. Parece que o "i" em seu primeiro lambda deve ser o índice do caractere na string. Isso funciona como deveria? Se sim, por que você reverte a string apenas para modificá-la com base na posição do índice? Parece um pouco redundante, não?
Nellius

Eu testei apenas um dos meus cartões de crédito e alguns com um erro dele, TBH. (Usando o depurador do VS 2008) O algoritmo deve dobrar a cada segundo dígito começando com o último dígito. Se eu não invertesse a string, seria incorreto para strings com comprimentos ímpares.
mootinator

Acontece que eu tive o resultado de i%2<1?1:2trás para a frente. Obrigado.
mootinator 02/02

8

Golfscript - 34 caracteres

{15&}%.-2%\);-2%{.+(9%)}%+{+}*10%!

Número de exemplo da página da wikipedia 4992739871

{15&}%  does a bitwise and of each ascii digit with 00001111
        now I have a list of digits 
        [4 9 9 2 7 3 9 8 7 1 6]
.       makes a copy of the list, now I have two identical lists
        [4 9 9 2 7 3 9 8 7 1 6] [4 9 9 2 7 3 9 8 7 1 6]
-2%     like [::-2] in python takes every second element in reverse
        [4 9 9 2 7 3 9 8 7 1 6] [6 7 9 7 9 4]
\       swap the two lists around
        [6 7 9 7 9 4] [4 9 9 2 7 3 9 8 7 1 6]
);      drop the last digit off the list
        [6 7 9 7 9 4] [4 9 9 2 7 3 9 8 7 1]
-2%     same as before
        [6 7 9 7 9 4] [1 8 3 2 9]
{       for each item in the list ...
.+      ... double it ...
(       ... subtract 1 ...
9%      ... mod 9 ...
)}%     ... add 1 ...
        [6 7 9 7 9 4] [2 7 6 4 9]
+       join the two lists
        [6 7 9 7 9 4 2 7 6 4 9]
{+}*    add the elements up
        70
10%     mod 10
        0
!       invert the result
        1

O .+(9%)é muito inovador (para mim, pelo menos). Eu gosto! +1
Chris Jester-Young

Porém, o GolfScript precisa de um operador de particionamento, para que você não precise fazer isso "solte o item final e repita" as bobagens. :-)
Chris Jester-Young

11
@ Chris, eu aprendi sobre isso há muitos anos chamado "lançando noves". É uma maneira elegante de duplas adições verificação longhand e multiplicações
gnibbler

3
Isso não funcionará para que o valor 0 seja dobrado ( 0(9%)é 9 e não 0).
Nabb

8

PHP, 108 bytes

<?function v($s,$t=0){for($i=strlen($s);$i>=0;$i--,$c=$s[$i])$t+=$c+$i%2*(($c>4)*-4+$c%5);return!($t % 10);}

7

Ruby - 85 caracteres

def f s
l=s.size
s.chars.map{|k|(i=k.to_i*((l-=1)%2+1))%10+i/10}.inject(:+)%10==0
end

Você provavelmente sabe sobre isso, mas você poderia fazer .sum vez de .inject (: +) para salvar 7 bytes
Håvard Nygård

7

Haskell, 96 bytes

Deve haver uma maneira melhor / mais curta, mas eis a minha solução Haskell em 96 caracteres :

l=(==0).(`mod`10).sum.zipWith($)(cycle[id,\x->x`mod`5*2+x`div`5]).reverse.map((+(-48)).fromEnum)

Infelizmente, a digitToIntfunção só pode ser usada se você import Data.Charprimeiro. Caso contrário, eu poderia diminuir para 88 caracteres substituindo ((+(-48)).fromEnum)por digitToInt.


6

Windows PowerShell, 82

filter f{!((''+($_[($_.length)..0]|%{+"$_"*($i++%2+1)})-replace'.','+$&'|iex)%10)}

História:

  • 2011-02-13 03:08 (84) Primeira tentativa.
  • 2011-02-13 12:13 (82) Não preciso entrar, pois os espaços não machucam. +1 + +3ainda pode ser avaliado.

5

Q, 63

{0=mod[(+/)"I"$(,/)($)($)@["I"$'x;1+2*'(!)(_)((#)x)%2;*;2];10]}

uso

q){0=mod[(+/)"I"$(,/)($)($)@["I"$'x;1+2*'(!)(_)((#)x)%2;*;2];10]}"79927398711"
0b
q){0=mod[(+/)"I"$(,/)($)($)@["I"$'x;1+2*'(!)(_)((#)x)%2;*;2];10]}"79927398712"
0b
q){0=mod[(+/)"I"$(,/)($)($)@["I"$'x;1+2*'(!)(_)((#)x)%2;*;2];10]}"79927398713"
1b

47 bytes com {0=mod[sum"J"$raze($)($)x*#:[x]#1 2]10}"I"$'(|)uma maneira diferente de duplicar os índices ímpares.
Streetster 21/10

5

D, 144 bytes

bool f(S)(S s){int t(C)(C c){return to!int(c)-'0';}int n,v;foreach(i,c;array(retro(s))){v=i&1?t(c)*2:t(c);n+=v>=10?v%10+v/10:v;}return n%10==0;}

Mais legível:

bool f(S)(S s)
{
    int t(C)(C c)
    {
        return to!int(c) - '0';
    }

    int n, v;

    foreach(i, c; array(retro(s)))
    {
        v = i & 1 ? t(c) * 2 : t(c);

        n += v >= 10 ? v % 10 + v / 10 : v;
    }

    return n % 10 == 0;
}

5

APL, 28 bytes

{0=10|+/⍎¨∊⍕¨v×⌽2-2|⍳⍴v←⍎¨⍵}

Vista expandida

{                     v←⍎¨⍵}  ⍝ turn the string into a numeric vector of its digits, v
                2-2|⍳⍴v       ⍝ make a vector of the same length, with 2 in every 2nd place
             v×⌽              ⍝ multiply it with v, starting from the right
          ∊⍕¨                 ⍝ turn each component into a string and collect all the digits
      +/⍎¨                    ⍝ turn each digit again into a number and sum them
 0=10|                        ⍝ check whether the sum is a multiple of 10

Exemplos

      {0=10|+/⍎¨∊⍕¨v×⌽2-2|⍳⍴v←⍎¨⍵} '79927398713'
1
      {0=10|+/⍎¨∊⍕¨v×⌽2-2|⍳⍴v←⍎¨⍵} '123456789'
0

11
-2:{0=10|+/⍎¨∊⍕¨⍵×⌽2-2|⍳⍴⍵}⍎¨
Adám 30/03

4

PowerShell 123

filter L($x){$l=$x.Length-1;$l..0|%{$d=$x[$_]-48;if($_%2-eq$l%2){$s+=$d}elseif($d-le4){$s+=$d*2}else{$s+=$d*2-9}};!($s%10)}

4

Perl, 46 42 41 bytes

Inclui +1 para -p

Dê entrada no STDIN:

luhn.pl <<< 79927398713

luhn.pl:

#!/usr/bin/perl -p
s%.%$=-=-$&-$&*1.2*/\G(..)+$/%eg;$_=/0$/

Você pode explicar como isso funciona? Você parece estar diminuindo pela partida e depois também pelos tempos 1,2, mas apenas nas posições corretas. Por que 1.2? Não deveria ser $=-=-$&-$&*/\G(..)+$/?
msh210

3
@ msh210: Codifica o efeito da multiplicação por 2. 0..4* 2 fornece 0, 2, 4, 6, 8mas 5..9fornece 10,12,14,16,18qual soma 1 3 5 7 9possui os mesmos últimos dígitos e 11 13 15 17 19quais são os mesmos valores como 0..9 * 2.2se você truncar para inteiro. O primeiro $&já contribui com um fator 1, portanto 1.2ainda é necessária uma correção por . $=só pode conter números inteiros e começa com um valor que termina em 0, para cuidar do truncamento. Os valores negativos são necessários uma vez que a /\G/regex altera qualquer $&ainda na pilha de avaliação para que eles precisam de ser alteradas
Ton Hospel

Oh. Brilhante! E obrigado pela explicação.
precisa saber é o seguinte

3

JavaScript (ES6), 61 bytes

Não concorrente, pois o JavaScript foi muito diferente em 2011.

A soma dos dígitos de 2*né 2*nse n in 0..4, 2*n-9se n in 5..9. Dito isto, toda a soma pode ser calculada em uma única etapa.

s=>!([...s].reduceRight((t,d)=>t-d-i++%2*(d>4?d-9:d),i=0)%10)

3

Geléia , 12 11 bytes

ṚḤJḤ$¦DFS⁵ḍ

Experimente online! (com todos os casos de teste)

Como funciona

ṚḤJḤ$¦DFSḍ⁵  - Main link. Argument: n (integer) e.g. 49927398716
Ṛ            - Reverse. Casts a number to digits     [6, 1, 7, 8, 9, 3, 7, 2, 9, 9, 4]
     ¦       - Sparse application. Apply the next command to the given indicies
 Ḥ           -   Command: Double
    $        -   Indicies:
  J          -     range(length)...                  [1, 2 , 3, 4, 5, 6, 7, 8, 9, 10, 11]
   Ḥ         -     doubled.                          [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
             - Doubles elements at odd indicies      [6, 2, 7, 16, 9, 6, 7, 4, 9, 18, 4]
      D      - Split each into digits                [6, 2, 7, [1, 6], 9, 6, 7, 4, 9, [1, 8], 4]
       F     - Flatten                               [6, 2, 7, 1, 6, 9, 6, 7, 4, 9, 1, 8, 4]
        S    - Sum                                   70
          ḍ  - Divisible by... 
         ⁵   -   10?                                 1

Como alternativa, para 12 bytes:

ṚḤJḤ$¦DFSḍ@⁵

3

x86-16 ASM , IBM PC DOS, 23 bytes

03 F1       ADD  SI, CX         ; start at end of input string 
FD          STD                 ; set LODSB direction to decrement 
    DIGIT_LOOP:
AC          LODSB               ; load next digit into AL, decrement SI
2C 30       SUB  AL, '0'        ; convert ASCII char to binary value 
F7 DA       NEG  DX             ; flip DX to alternate odd/even index
78 06       JS   EVEN           ; if even index, do not double and sum digits 
D0 E0       SHL  AL, 1          ; double the value 
D4 0A       AAM                 ; BCD convert to split digits (ex: 18 = 12H --> 0108H) 
02 DC       ADD  BL, AH         ; add tens digit to running sum 
    EVEN:
02 D8       ADD  BL, AL         ; add ones digit to running sum 
E2 ED       LOOP DIGIT_LOOP 
93          XCHG BX, AX         ; sum is in BL, move to AL for conversion
D4 0A       AAM                 ; BCD convert AL, set ZF=1 if low digit is 0

Utiliza (abusa) a instrução BCD para binário do x86 AAMpara lidar com a divisão e modulo 10verificação de dígitos individuais .

Numero do cartão de entrada em ponteiro SI, comprimento em CX. Saída: ZFse válido.

Exemplo de saída do programa de teste:

insira a descrição da imagem aqui

Faça o download do programa de teste LUHN.COM IBM PC DOS.


2

Scala: 132

def q(x:Int)=x%10+x/10
def c(i:String)={val s=i.reverse
(s(0)-48)==10-(s.tail.sliding(2,2).map(n=>(q((n(0)-48)*2)+n(1)-48)).sum%10)}

invocação:

c("79927398713")
  • reverse ("79927398713") = 31789372997
  • s (0), s.tail: (3) (1789372997)
  • deslizamento (2,2) = (17 89 37 29 97)
  • map (q ((n (0) -48 * 2 + n (1) -48)) => q (('1' - '0') * 2) + '7' - '0') = 1 * 2 + 7

2

JavaScript 1.8: 106 caracteres

Esta é uma solução original que eu criei antes de encontrar este post:

function(n){return!(n.split('').reverse().reduce(function(p,c,i){return(+c&&((c*(1+i%2)%9)||9))+p},0)%10)}

Formulário legível:

function luhnCheck(ccNum) {
    return !(                                  // True if the result is zero.
             ccNum.split('').
               reverse().                      // Iterate over the string from rtl.
               reduce(function(prev, cur, idx) {
                 return prev +                 // Sum the results of each character.
                        (+cur &&               // If the current digit is 0, move on.
                         ((cur * (1 + idx % 2) // Double cur at even indices.
                           % 9) || 9));        // Sum the digits of the result.
               }, 0)
            % 10);                             // Is the sum evenly divisible by 10?
}


2

Retina , 43 42 bytes

A retina é (muito) mais nova que esse desafio.


;
r`(.);.
$1$&
\d
$*
1+
$.&
.
$*
$
$._
0$

A linha vazia principal é significativa.

Imprime 0para obter 1resultados falsos e verdadeiros .

Experimente online! (Ligeiramente modificado para executar todos os casos de teste de uma vez.)

Explicação


;

Insira ;em todas as posições para separar dígitos.

r`(.);.
$1$&

Desde a rnoite, combinamos repetidamente dois dígitos e dobramos o esquerdo. Dessa forma, evitamos uma inversão cara da lista.

\d
$*

Combinamos cada dígito e o convertemos em muitos 1s (ou seja, convertemos cada dígito em unário).

1+
$.&

Isso corresponde a cada número unário e o converte novamente em decimal, substituindo-o pelo seu comprimento. Juntamente com o estágio anterior, isso adiciona os dígitos dobrados.

.
$*

Novamente, combinamos todos os personagens e transformamos em muitos 1s. Ou seja, convertemos cada dígito individualmente novamente em unário. Isso também corresponde aos ;separadores, que são tratados como zeros na conversão, o que significa que eles são simplesmente removidos. Como todos os números unários agora estão compactados, adicionamos automaticamente as representações unárias de todos os dígitos.

$
$._

No final, inserimos o comprimento de toda a cadeia, ou seja, a representação decimal da soma de verificação unária.

0$

Finalmente, contamos o número de correspondências desse regex, ou seja, verificamos se a representação decimal termina em 0, imprimindo 0ou em 1conformidade.


2

Powershell, 74 bytes

param($s)$s[$s.Length..0]|%{(1+$i++%2)*"$_"}|%{$r+=$_-9*($_-gt9)}
!($r%10)

Explicação

  1. para cada caractere de uma sequência de argumentos, em ordem inversa
  2. obter um dígito com o dobro do valor de um dígito
  3. um valor duplo de um dígito não pode ser superior a 18. Portanto, acumulamos um valor menos 9 se valor> 9
  4. return true se o restante da divisão por 10 for 0

Script de teste

$f = {

param($s)$s[$s.Length..0]|%{(1+$i++%2)*"$_"}|%{$r+=$_-9*($_-gt9)}
!($r%10)

}

@(
    ,("49927398716"      , $True)
    ,("49927398717"      , $False)
    ,("1234567812345670" , $True)
    ,("1234567812345678" , $False)
    ,("79927398710"      , $False)
    ,("79927398711"      , $False)
    ,("79927398712"      , $False)
    ,("79927398713"      , $True)
    ,("79927398714"      , $False)
    ,("79927398715"      , $False)
    ,("79927398716"      , $False)
    ,("79927398717"      , $False)
    ,("79927398718"      , $False)
    ,("79927398719"      , $False)
    ,("374652346956782346957823694857692364857368475368" , $True)
    ,("374652346956782346957823694857692364857387456834" , $False)
    ,("8" , $False)
    ,("0" , $True)
) | % {
    $s, $expected = $_
    $result = &$f $s
    "$($result-eq$expected): $result : $s"
}

Resultado

True: True : 49927398716
True: False : 49927398717
True: True : 1234567812345670
True: False : 1234567812345678
True: False : 79927398710
True: False : 79927398711
True: False : 79927398712
True: True : 79927398713
True: False : 79927398714
True: False : 79927398715
True: False : 79927398716
True: False : 79927398717
True: False : 79927398718
True: False : 79927398719
True: True : 374652346956782346957823694857692364857368475368
True: False : 374652346956782346957823694857692364857387456834
True: False : 8
True: True : 0

2

05AB1E , 12 10 bytes

RSāÈ>*SOTÖ

Experimente online! ou como um conjunto de testes

Explicação

R             # reverse input
 S            # split to list of digits
  ā           # push range[1 ... len(input)]
   È          # map isEven on each
    >         # increment
     *        # multiply doubling every other item
      SO      # sum digits
        TÖ    # mod 10 == 0


1

GNU sed, 140 bytes

(incluindo +1 para a -rbandeira)

s/^(..)*.$/0&/
s/(.)./\1x&/g
s/x[5-9]/1&/g
s/[0x]//g
s/[789]/&6/g
s/[456]/&3/g
s/[369]/&11/g
s/[258]/&1/g
s/.{10}//g
s/.+/false/
s/^$/true/

Sed quase nunca é a linguagem mais natural para a aritmética, mas aqui vamos nós:

#!/bin/sed -rf

# zero-pad to even length
s/^(..)*.$/0&/
# double every other digit
s/(.)./\1x&/g
# add carry (converts mod-9 to mod-10)
s/x[5-9]/1&/g
# convert sum to unary
s/[0x]//g
s/[789]/&6/g
s/[456]/&3/g
s/[369]/&11/g
s/[258]/&1/g
# remove whole tens
s/.{10}//g
# output 'true' or false
s/.+/false/
s/^$/true/

1

APL, 38 bytes

d←10∘⊥⍣¯1⋄{0=10|+/+/d x×1+~2|⍳⍴x←⌽d ⍵}

espera o número como um número, não como uma string, mas é apenas porque o tryAPL (compreensivelmente) não implementa

mais redutível, tenho certeza ...


1

PHP - 136 caracteres

function t($c){foreach($a=str_split(strrev($c)) as $k=>&$v){$v=array_sum(str_split(($k % 2)!==0?2*$v:$v));}return !(array_sum($a)% 10);}

1

MATL , 23 20 bytes (não concorrente)

P!Utn:2X\!*t9>+s10\~

Experimente online!

Saídas 1 para um número válido, 0 caso contrário.

Economizou três bytes graças às sugestões de Luis Mendo.

Explicação

P       % flip the order of elements
!       % transpose into column vector
U       % convert char matrix to numeric
t       % duplicate the vector
n       % find the length
:       % create a new vector length n (1, 2, 3, ... n)
2       % number literal
X\      % take it mod 2, to make the new vector (1, 2, 1, ..., (n-1) mod 2 +1)
!       % transpose
*       % element-wise product
t       % duplicate
9       % push 9
>       % 1 if it is greater than 9
+       % add the vectors, this makes the last digit of each the same as the sum of the digits
s       % add them
10      % number literal
\       % mod 10
~       % logical 'not' (element-wise)
        % (implicit) convert to string and display

1

Gelatina , 14 bytes

DUḤJḤ$¦DS$€S⁵ḍ

Experimente online!

Explicação:

D              get digits
 U             reverse array
   JḤ$         for every other index,
  Ḥ   ¦        double the value
          €    for each value,
       D $     get the digits
        S$     and sum them
           S   sum the list
            ⁵ḍ check if it's divisible by 10

Por que isso não é competitivo?
usar o seguinte código

@ mudkip201 Corrija-me se estiver errado, mas esta versão do Jelly não existia quando a pergunta foi feita, por isso não é válida para a pergunta.
Ellie

3
Certeza que havia uma meta consenso de que disse que as línguas que foram feitas após o desafio não são 'não concorrentes' mais
mudkip201
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.