Reduzir string para um trecho de alfabeto


25

Dada uma sequência não vazia que consiste apenas em caracteres e espaços alfabéticos em maiúsculas e minúsculas ( [a-zA-Z ]), reduza-a a um trecho do alfabeto, começando com o primeiro caractere.

Para reduzir uma string, comece com o primeiro caractere alfabético e remova todos os caracteres que não sejam a próxima letra do alfabeto. Continue fazendo isso até chegar ao final da string.

Por exemplo codegolf:

Comece com c, remova, opois não é a próxima letra do alfabeto.
Mantenha dcomo é a próxima letra do alfabeto e mantenha ecomo também é a próxima letra.
Remover g, oe l, e manter f.

Seu snippet final seria então cdef

Regras

  • A capitalização deve ser mantida, o CodEgolFque resultaria emCdEF
  • O espaço não é uma letra do alfabeto e, portanto, sempre deve ser removido, mesmo que seja o início da string
  • Devido à natureza da redução, o primeiro caractere alfabético da entrada será sempre o primeiro caractere da saída.
  • zZé a última letra do alfabeto. Não há letras depois, o alfabeto não se repete.

Casos de teste

codegolf -> cdef
CodEgolf -> CdEf
 codeolfg -> cdefg
ProgrammingPuzzles -> P
Stack Exchange -> St
The quick red fox jumped over the lazy brown dog -> Tuvw
Zebra -> Z
Abcdegfhijkl -> Abcdef

Pontuação

Isso é , e o menor número de bytes em cada idioma vence!


Desde o segundo último caso de teste, vejo que, se chegarmos, zapenas paramos, certo?
Mr. Xcoder

@ Mr.Xcoder Correto, veja o último ponto em "Regras"
Skidsdev 17/08/17

2
Adicione um caso de teste com um espaço no início. Como:<space>codegolf
Sr. Xcoder

Posso retornar uma matriz das letras de saída?
TheLethalCoder

1
@ Mr.Xcoder sim você pode
Skidsdev

Respostas:


12

JavaScript (ES6), 66 79 68 67 bytes

f=([c,...s],p)=>c?(p?~parseInt(c+p,36)%37:c<'!')?f(s,p):c+f(s,c):''

Quão?

Testando letras consecutivas

Como converter dois caracteres em seus códigos ASCII seria uma operação bastante demorada em JS, em vez disso, usamos a seguinte fórmula:

~parseInt(b + a, 36) % 37

Desde que ambos um e b são em [a-zA-Z ], a expressão acima é igual a 0, se e apenas se um e b são letras consecutivas (isto é, os dígitos consecutivos na base 36), não importa o caso dos caracteres.

Por exemplo:

~parseInt("Y" + "x", 36) = ~(36 * parseInt("Y", 36) + parseInt("x", 36))
                         = ~(36 * 34 + 33)
                         = -(36 * 34 + 33 + 1)
                         = -(37 * 34)

Formatado e comentado

f = ([c,                              // c = current character
         ...s],                       // s = array of remaining characters
                p) =>                 // p = previous matching letter
  c ? (                               // if there's still at least 1 character to process:
      p ?                             //   if p was already defined:
        ~parseInt(c + p, 36) % 37     //     test if p and c are NON-consecutive letters
      :                               //   else:
        c < '!'                       //     test if c is a space character
    ) ?                               //   if the above test passes:
      f(s, p)                         //     ignore c and keep the current value of p
    :                                 //   else:
      c + f(s, c)                     //     append c to the final result and update p to c
  :                                   // else:
    ''                                //   stop recursion

Casos de teste


7

Python 2 , 69 bytes

lambda s:reduce(lambda x,y:x+y*((ord(y)-ord(x[~0]))%32==1),s.strip())

Experimente online!

Uma simples redução da string. Simplesmente concatenamos o próximo caractere se e somente se (ord(y)-ord(x[~0]))%32==1. Cheque muito feio - tenho certeza de que pode ser melhorado, mas não sei como!


Solução inteligente! Pena que é apenas Python 2: P #
Mr. Xcoder 17/17/17

Você pode torná-lo compatível com o Python 3 com from functools import*.
totallyhuman

1
O @ThomasWard totallyhuman estava apenas dizendo aos outros como torná-lo compatível com o Python 3. Btw, import functools as fe f.é muito mais longo do que from functools import*com certeza, mesmo usado uma vez. Veja este tópico para mais informações.
Mr. Xcoder

7

Python 3 , 75 85 84 91 81 77 75 bytes

Eu acho que isso é o mais curto possível no Python 3 . Pode ser reduzido por alguns bytes no Python 2, como mostra o envio de Sisyphus .

  • EDIT: +10 para corrigir um erro
  • EDIT: -1 corrigindo outro bug
  • EDIT: +7 para corrigir outro bug
  • EDIT: -10 bytes com ajuda do @Ruud
  • EDIT: -4 bytes desde que o OP nos permitiu produzir as letras separadas por uma nova linha
  • EDIT: -2 bytes graças a @Ruud , de volta à contagem de bytes original!
s=input().strip();k=0
for i in s:
 if(ord(i)-ord(s[0]))%32==k:k+=1;print(i)

Experimente online!


Tenho idéias para melhorar, jogar golfe no celular em breve.
Mr. Xcoder

2
81 bytes . As letras maiúsculas e minúsculas convenientemente corresponder quando modulada por 32
Arfie

@ Ruud Essas são exatamente as coisas que eu estava falando no meu comentário, edição.
Mr. Xcoder


8
Estou esperando que o downvoter explique suas razões.
Mr. Xcoder


4

Braquilog , 15 bytes

;ṢxS⊇.ḷ~sẠ∧Sh~h

Experimente online!

Seriam 10 bytes: ⊇.ḷ~sẠ&h~hse não fosse a restrição bastante desinteressante de "cadeias podem começar com espaços".

Explicação

;ṢxS               S is the Input with all spaces removed
   S⊇.             The Output is an ordered subset of the Input
     .ḷ            The Output lowercased…
        ~sẠ          …is a substring of "abcdefghijklmnopqrstuvwxyz"
           ∧
            Sh     The first char of S…
              ~h   …is the first char of the Output

Como isso é bastante declarativo, isso também é muito lento.


Bem, pelo menos, bate Jelly! E, do lado positivo, não acho que você possa realmente superar isso ...
Erik the Outgolfer

3

MATL , 18 16 15 bytes

Agradecemos ao Mr.Xcoder por apontar um erro, agora corrigido

Xz1&)"t@hkd1=?@

As letras na saída são separadas por novas linhas.

Experimente online! Ou verifique todos os casos de teste (o código do rodapé exibe todas as letras de saída na mesma linha para maior clareza).

Explicação

Xz       % Implicitly input a string. Remove spaces
1&)      % Push first character and then the remaining substring
"        % For each
  t      %   Duplicate previous character
  @      %   Push current character
  h      %   Concatenate both characters
  k      %   Convert to lowercase
  d      %   Consecutive difference. Gives a number
  1=     %   Is it 1?
  ?      %   If so
    @    %     Push current char
         %   End (implicit)
         % End (implicit)
         % Display stack (implicit)

Você esqueceu de remover os espaços quando eles estão no início da sequência: Espaço não é uma letra do alfabeto e, portanto, sempre deve ser removida, mesmo que seja o início da sequência .
Mr. Xcoder

@ Mr.Xcoder Obrigado! Corrigido
Luis Mendo


2

C # (Mono) , 129 107 93 91 87 bytes

s=>{var r=s.Trim()[0]+"";foreach(var c in s)if(r[r.Length-1]%32==~-c%32)r+=c;return r;}

Economizou 2 bytes graças a @Mr. Xcoder.
Guardado 4 bytes graças a @jkelm.

Experimente online!


Falha nos espaços à esquerda
Skidsdev 17/08/2017

@ Mayube Woops não viu isso, consertado.
TheLethalCoder

2
91 bytes . Nas linguagens C e Python, (c-1)%32é:~-c%32
Sr. Xcoder 17/08/19

1
87 bytes Você não precisa atribuir novamente a corda cortada por causa das verificações no loop
jkelm

2

PHP, 64 + 1 bytes

while($c=$argn[$i++])$c<A||$n&&($c&_)!=$n||(print$c)&$n=++$c&__;

Execute como pipe -nRou experimente online .


Além dos truques habituais: Quando $calcances Z, ++$cresulta em AA,
e &__mantém que o comprimento intocada; então $nnão corresponderá mais $c.




2

Pitão, 21 20 18 bytes

ef&qhThQhxGrT0tyr6

Experimente aqui.

Muito mais eficiente versão de 20 bytes:

.U+b?t-CrZ1Creb1kZr6

Experimente aqui.

-1 graças ao Sr. Xcoder (indiretamente).


Equivalente: .U+b?tlrreb1rZ1kZrz6(eu acho). Esse truque me ajudou embora.
Mr. Xcoder

@ Mr.Xcoder Se isso fosse equivalente, eu poderia ter salvo um byte, .U+b?tlrreb1rZ1kZr6mas infelizmente r <str> 6significa A.strip()não remover o espaço em branco que não é líder ou à direita.
Erik the Outgolfer

Oh yeah, eu não vi a sua solução depende de todos os espaços a serem removidos (o meu não)
Mr. Xcoder

@ Mr.Xcoder Umm, você deve remover todos os espaços.
Erik the Outgolfer

Não, não deveria, pois o espaço tem um valor ASCII de 32, enquanto todas as letras têm > 64e, portanto, não afetam a funcionalidade. Eu acho que isso se aplica à sua resposta também.
Mr. Xcoder

1

Perl 6 , 51 bytes

{S:i:g/\s|(\w){}<([<!before "{chr $0.ord+1}">.]+//}

Teste-o

Expandido:

{  # bare block lambda with implicit parameter $_

  S                          # substitute implicitly on $_, not in-place
  :ignorecase
  :global
  /

    |  \s                    # match any space

    |  (\w)                  # match a word character
       {}                    # make sure $/ is updated (which $0 uses)

       <(                    # ignore everything before this

       [

           <!before "{       # make sure this won't match after this point
             chr $0.ord + 1  # the next ASCII character
           }">

           .                 # any character

       ]+                    # match it at least once

  //                         # remove what matched
}

Observe que <!before …>é uma asserção de largura zero



1

Japt , 18 17 16 bytes

Guardado 1 byte graças a @Shaggy

x
c
Çc %H¥V%H©V°

Teste online!

Estava pensando que isso seria um pouco mais curto, mas ... Essa é a vida ...

Explicação

x    First line: set U to the result.
x    Trim all spaces off of the input. Only necessary to remove leading spaces.

c    Second line: set V to the result.
c    Take the charcode of the first character in U.

 Ç   c %H¥ V%H© V°
UoZ{Zc %H==V%H&&V++}   Final line: output the result.
UoZ{               }   Filter to only the chars in Z where
    Zc                   the charcode of Z
       %H                mod 32
         ==V%H           equals V mod 32.
              &&V++      If true, increment V for the next letter.

Mais curto do que o meu travesti de 28 bytes, pelo menos! : D Parece que você pode substituir rSpor x.
Shaggy

1

C # (.NET Core) , 70 60 + 18 bytes

-10 bytes graças a TheLethalCoder

a=>{var c=a.Trim()[0];return a.Where(x=>x%32==c%32&&++c>0);}

A contagem de bytes também inclui:

using System.Linq;

Experimente online!

1 byte a mais (atualmente) (não mais) do que a publicação TheLethalCoder, por diversão. Abordagem diferente, com o LINQ.

Isso tira proveito de dois recursos do tipo C em C # - uma charvariável de caractere está se comportando implicitamente da mesma forma que um número inteiro inte o operador booleano AND &&não executa a operação correta se a esquerda retornar a false. Explicação do código:

a =>                                  // Take string as input
{
    var c = a.Trim()[0];              // Delete leading spaces and take first letter
    return a.Where(                   // Filter out characters from the string, leaving those that:
               x => x % 32 == c % 32  // it's the next character in alphabet case-insensitive (thanks to modulo 32 - credits to previous answers)
               && ++c > 0             // If it is, go to the subsequent character in alphabet (and this always has to return true)
           );
}

Remova o .ToArray()retornando como um IEnumerable<char>para salvar bytes.
TheLethalCoder

@TheLethalCoder certo, acabei de ver o comentário sob o desafio. Obrigado!
Grzegorz Puławski

1

q / kdb +, 47 45 bytes

Solução:

{10h$({(x;x,y)1=mod[y-last x;32]}/)7h$trim x}

Exemplos:

q){"c"$({(x;x,y)1=mod[y-last x;32]}/)7h$trim x}"CodEgolf"
"CdEf"
q){"c"$({(x;x,y)1=mod[y-last x;32]}/)7h$trim x}" codeolfg"
"cdefg"
q){"c"$({(x;x,y)1=mod[y-last x;32]}/)7h$trim x}"ProgrammingPuzzles"
"P"
q){"c"$({(x;x,y)1=mod[y-last x;32]}/)7h$trim x}"The quick red fox jumped over the lazy brown dog"
"Tuvw"

Explicação:

Aproveitando o mod 32truque das soluções existentes, juntamente com a função de convergência . Itere sobre a sequência, se a diferença entre o último elemento do resultado (por exemplo, começar com T"A raposa vermelha rápida ...") e o caractere atual for 1 (depois de ser modd com 32), adicionaremos isso a o resultado (daí entendermos o motivo last x), e depois converter tudo em uma string.

{10h$({(x;x,y)1=mod[y-last x;32]}/)7h$trim x} / the solution
{                                           } / lambda function
                                      trim x  / trim whitespace (leading/trailing)
                                   7h$        / cast string to ASCII (a -> 97)
     ({                         }/)           / converge
                    y-last x                  / y is the next item in the list, x contains results so far
              1=mod[        ;32]              / is the result mod 32 equal to 1
       (x;x,y)                                / if false, return x, if true return x concatenated with y
 10h$                                         / cast back to characters

1

Perl 5 , 30 + 1 (-n) = 31 bytes

/$b/i&&(print,$b=++$_)for/\S/g

Experimente online!

Quão?

/$b/i        # check if this letter equals the one in $b, ignore case
&&(print,    # output it if so
$b=++$_)     # store the next character to find
for/\S/g     # Looping over all non-whitespace characters

0

Retina , 76 bytes

 

^.
$&$&$&¶
{T`@@L@l`@l@l@`..¶
T`l`L`.¶
(.)(.)((¶).*?(\1|\2)|¶.*)
$5$5$5$4

Experimente online! O link inclui casos de teste. Explicação:

 

Excluir espaços.

^.
$&$&$&¶

Triplicar o primeiro caractere e inserir um separador.

{T`@@L@l`@l@l@`..¶
T`l`L`.¶

Converta o segundo e o terceiro caracteres em minúsculas e incremente-os. Converta o último para maiúsculas. Agora, esses são os caracteres de pesquisa.

(.)(.)((¶).*?(\1|\2)|¶.*)
$5$5$5$4

Tente combinar com qualquer um dos caracteres de pesquisa. Se encontrado, triplique a correspondência, que reinicia o loop para a próxima pesquisa. Caso contrário, basta excluir os caracteres de pesquisa e o restante da entrada.


0

Oitavo , 114 bytes

Código

: z dup n:1+ 32 bor >r "" swap s:+ . ; 
: f s:trim 0 s:@ z ( nip dup 32 bor r@ n:= if rdrop z then ) s:each rdrop ;

Explicação

: z             \ n -- (r: x)
                \ print letter and save on r-stack OR-bitwised ASCII code of following letter
  dup           \ duplicate item on TOS
  n:1+          \ get ASCII code of the following letter
  32 bor        \ bitwise OR of ASCII code and 32 
  >r            \ save result on r-stack
  "" swap s:+ . \ print letter
;

: f        \ s -- 
  s:trim   \ remove trailing whitespace
  0 s:@    \ get 1st letter
  z        \ print 1st letter and save on r-stack OR-bitwised ASCII code of following letter
  ( nip    \ get rid of index
    dup    \ duplicate item on TOS
    32 bor \ bitwise OR of current ASCII code and 32 
    r@     \ get value stored on r-stack
    n:=    \ compare values to see if letter is printable or not
    if 
      rdrop \ clean r-stack
      z     \ print letter and save on r-stack OR-bitwised ASCII code of following letter
    then 
  ) 
  s:each    \ handle each character in string
  rdrop     \ clean r-stack
;

Exemplo

ok> " The quick red fox jumped over the lazy brown dog" f
Tuvw



0

Pitão, 15 bytes

eo,}r0NG_xQhNty

Suíte de teste

Diferentemente de todas as outras respostas, isso não une a saída, gera todas as subsequências da entrada e, em seguida, ordena que colocem a sequência desejada no final e a produz.


Eu acho que você tem que verificar se a primeira letra da saída é a primeira letra da entrada também. E acho que a ordem inicial é importante.
Erik the Outgolfer

@EriktheOutgolfer Desculpe, você está dizendo que a resposta está errada? Garanto que a sequência cujo primeiro caractere seja o mais antigo na entrada, entre todas as subsequências alfabéticas, seja a ordenada até o fim. Veja o caso de teste começando com um espaço.
Isaacg

Você pode adicionar uma explicação, por favor? Talvez eu tenha entendido mal ou algo assim ...
Erik o Outgolfer

0

J, solução parcial

Estou postando isso para feedback e idéias para melhorias mais do que qualquer outra coisa. Funciona, mas não lida com os casos de capitalização e borda de espaço, e já é longo para J.

Primeiro, um verbo diádico auxiliar que informa se os argumentos esquerdo e direito são alfabeticamente adjacentes:

g=.(= <:)&(a.&i.)  NB. could save one char with u:

A seguir, um verbo que remove o primeiro elemento que não faz parte de uma sequência alfabética iniciando no primeiro elemento:

f=.({~<^:3@>:@i.&0@(0,~2&(g/\))) ::]

Note que usamos Adverse :: para retornar o argumento inteiro inalterado se não for encontrado nenhum elemento que não seja de raia (ou seja, se o argumento inteiro for uma raia alfabética válida).

Finalmente, a solução é dada aplicando faté a convergência:

f^:_ 'codegolf'  NB. => 'cdef'

Experimente online!


E aqui está uma versão analisada fpara facilitar a leitura:

           ┌─ ~ ─── {                         
           │                              ┌─ <
           │                       ┌─ ^: ─┴─ 3
           │                 ┌─ @ ─┴─ >:      
       ┌───┤           ┌─ @ ─┴─ i.            
       │   │     ┌─ & ─┴─ 0                   
       │   │     │                            
       │   └─ @ ─┤     ┌─ 0                   
── :: ─┤         │     ├─ ~ ─── ,             
       │         └─────┤                      
       │               │     ┌─ 2             
       │               └─ & ─┴─ \ ─── / ──── g
       └─ ]         

Pergunta lateral : por que os caracteres da caixa não se alinham perfeitamente quando exibidos no SO (eles funcionam no meu console):

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.