A melhor solução que encontrei até agora para um quebra-cabeça de código de golfe em que estou trabalhando inclui duas invocações bastante gordasrange
. Sou muito novo em código de golfe, especialmente em Python, para poder usar algumas dicas.
O fragmento relevante é este
[x for x in range(n+1,7**6)if`x`==`x`[::-1]*all(x%i for i in range(2,x))]
O limite superior do primeiro range
não é nítido. Deveria ser pelo menos 98690, e todo o resto ser igual (ou seja, em termos de golfe), quanto menor a diferença entre esse limite superior e 98690, melhor e em termos de desempenho 1 . Estou usando 7 6 (= 117649) porque 7**6
é a expressão Python mais curta que eu posso apresentar que se encaixa na conta.
Por outro lado, o limite inferior no primeiro range
e os dois no segundo são firmes. IOW, o programa (em sua forma atual) produzirá resultados incorretos se esses limites forem alterados.
Existe uma maneira de encurtar uma ou ambas as expressões
range(n+1,7**6)
range(2,x)
?
Aliás, neste caso, aliasing range
, digamos, r
não ganha nada:
r=range;rr
rangerange
EDIT: FWIW, o programa completo é o seguinte:
p=lambda n:[x for x in range(n+1,7**6)if`x`==`x`[::-1]*all(x%i for i in range(2,x))][0]
p(n)
deve ser o menor primo palindrômico maior que n
. Além disso, p
não deve ser recursivo. Aviso: já é obscenamente lento!
1 Sim, eu sei: o desempenho é irrelevante no código de golfe, mas foi por isso que escrevi "todo o resto é igual (em termos de golfe)". Por exemplo, minha escolha de 7**6
, e não a alternativa mais imediatamente óbvia, mas com pior desempenho e "equivalente ao golfe" 9**9
. Eu realmente gosto de executar minhas tentativas de código de golfe, o que significa não deixar o desempenho degradar a ponto de levar anos para executar o código. Se eu puder ajudar, é claro.
p=lambda n:(x for x in xrange(n+1,7**6)if`x`==`x`[::-1]*all(x%i for i in xrange(2,x))).next()
. Claro que, quando seu isso, poderia muito bem mudarxrange(2,x)
paraxrange(2,int(x**.5+1))
e fazer o seu teste muito rápido. Claramente, esse código é equivalente ao seu, apenas mais longo e mais rápido.Respostas:
Torná-lo um loop único
Como é, você tem dois loops: um repetindo
x
que pode ser primos palindrômicos, outro repetindoi
para verificar sex
é primo pela divisão de teste. Como você notou, o loops é que o Python ocupa muitos caracteres, geralmente para escreverrange
, mas também para escreverwhile _:
oufor x in _
. Portanto, uma solução Python para golfe deve fazer o possível para usar o menor número possível de loops.O comentário de feersum "Os programas com o melhor golfe geralmente fazem conexões surpreendentes entre diferentes partes dos programas" é muito aplicável aqui. A verificação primária pode parecer uma sub-rotina separada para a qual
all(x%i for i in range(2,x))
é a expressão clássica. Mas faremos de outra maneira.A idéia é usar o Teorema de Wilson . Para cada potencial prime
k
, mantemos um produto em execução(k-1)!
e verificamos se é um múltiplo dek
. Podemos acompanhar(k-1)!
enquanto testamos o potencialk
de serem os principais palíndromos mantendo um produto em execuçãoP
.Na verdade, usaremos a versão mais forte do Teorema de Wilson, que
(k-1)! % k
é igual a 0 parak
números compostos e apenas para números compostos, exceto no caso dek=4
doações2
e, portanto, exatamente(k-1)!**2 % k
igual0
aos números compostos. AtualizaremosP
para igualk!**2
pela atualizaçãoP*=k*k
.(Veja esta resposta para este método usado para encontrar números primos em Python.)
Juntando tudo:
Isso ainda não foi totalmente praticado - a condição em particular é escrita de maneira ineficiente. Podemos comprimir a condição para verificar se
k
é um palíndromo e, ao mesmo tempo, impor outras condições por meio de uma desigualdade encadeada.fonte
str
, mas esses truques só conseguem um muito ... as grandes melhorias vêm de algoritmos melhores, como sempre.`k`*(k>n)*(P%k>0)!=`k`[::-1]
que raspa 4AFAIK, na verdade não.
O alcance é comumente usado em golfinhos python porque é a maneira mais curta de gerar listas de números crescentes / decrescentes.
Dito isto, parece ser um pouco (7 bytes) mais curto para evitar o uso do range e, em vez disso, chamar um loop while empacotado:
Obrigado a @xnor (como sempre) por melhorar a lógica da condição while :)
fonte
while(`n`!=`n`[::-1])+0in(n%i for i in range(2,n)):n+=1
. Não consigo me livrar do primeiro par de parênteses devido a problemas de precedência do operador.while`n`*all(n%i for i in range(2,n))!=`n`[::-1]:n+=1
Ao usar algoritmos iterativos, como o método Newton ou calcular fractais, em que você geralmente precisa executar iterações sem realmente se importar com o índice, você pode salvar alguns caracteres, iterando sobre cadeias curtas.
Em sete iterações, isso se iguala
range
. Para mais iterações, use backtics e grandes númerosIsso é executado 56349 vezes, o que deve ser suficiente para todos os fins práticos. Brincar com números e operadores permite codificar uma grande variedade de números dessa maneira.
fonte
'1'*4
é menor do que'asdf'
)