Reduce la cadena a un fragmento del alfabeto


25

Dada una cadena no vacía que consta de solo caracteres alfabéticos en mayúsculas y minúsculas y espacios ( [a-zA-Z ]), reduzca a un fragmento del alfabeto, comenzando con el primer carácter.

Para reducir una cadena, comience con el primer carácter alfabético, luego elimine todos los caracteres que no sean la siguiente letra del alfabeto. Continúa haciendo esto hasta llegar al final de la cadena.

Por ejemplo codegolf:

Comience con c, elimine oya que no es la siguiente letra del alfabeto.
Mantenga dcomo es la siguiente letra del alfabeto, y mantenga ecomo es la siguiente letra también.
Retire g, oy l, y mantener f.

Su fragmento final sería entonces cdef

Reglas

  • La capitalización debe mantenerse, por CodEgolFlo que daría como resultadoCdEF
  • El espacio no es una letra del alfabeto y, por lo tanto, siempre debe eliminarse, incluso si es el comienzo de la cadena
  • Debido a la naturaleza de la reducción, el primer carácter alfabético de la entrada siempre será el primer carácter de la salida.
  • zZEs la última letra del alfabeto. No hay letras después, el alfabeto no se repite.

Casos de prueba

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

Tanteo

Este es el , ¡por lo que gana menos bytes en cada idioma !


Desde el segundo último caso de prueba, veo que si llegamos z, simplemente nos detenemos, ¿verdad?
Sr. Xcoder

@ Mr.Xcoder Correcto, vea el último punto en "Reglas"
Skidsdev

2
Agregue un caso de prueba con un espacio al principio. Como:<space>codegolf
Sr. Xcoder

¿Puedo devolver una matriz de las letras de salida?
TheLethalCoder

1
@ Mr.Xcoder sí puedes
Skidsdev

Respuestas:


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):''

¿Cómo?

Probar letras consecutivas

Debido a que convertir dos caracteres a sus códigos ASCII sería una operación bastante larga en JS, en su lugar utilizamos la siguiente fórmula:

~parseInt(b + a, 36) % 37

Siempre que tanto a como b estén dentro [a-zA-Z ], la expresión anterior es igual 0si y solo si a y b son letras consecutivas (es decir, dígitos consecutivos en la base 36), sin importar el caso de los caracteres.

Por ejemplo:

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

Formateado y 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 prueba


7

Python 2 , 69 bytes

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

Pruébalo en línea!

Una simple reducción de la cuerda. Simplemente concatenamos el siguiente carácter si y solo si (ord(y)-ord(x[~0]))%32==1. Verificación muy fea: estoy seguro de que se puede mejorar, ¡pero no estoy seguro de cómo!


Solución inteligente! Lástima que solo sea Python 2: P
Mr. Xcoder

Puede hacerlo compatible con Python 3 con from functools import*.
totalmente humano

1
@ThomasWard totalmente humano solo le estaba diciendo a otros cómo hacerlo compatible con Python 3. Por cierto, import functools as fy f.es mucho más largo que from functools import*seguro, incluso se usa una vez. Vea este hilo para más información.
Sr. Xcoder

7

Python 3 , 75 85 84 91 81 77 75 bytes

Creo que esto es lo más corto posible en Python 3 . Se puede acortar en unos pocos bytes en Python 2, como se muestra en el envío de Sisyphus .

  • EDITAR: +10 para corregir un error
  • EDITAR: -1 arreglando otro error
  • EDITAR: +7 para arreglar otro error
  • EDITAR: -10 bytes con ayuda de @Ruud
  • EDITAR: -4 bytes ya que el OP nos permitió generar las letras separadas por una nueva línea
  • EDITAR: -2 bytes gracias a @Ruud , ¡de vuelta al recuento de bytes original!
s=input().strip();k=0
for i in s:
 if(ord(i)-ord(s[0]))%32==k:k+=1;print(i)

Pruébalo en línea!


Tengo ideas para mejorar, jugar golf en dispositivos móviles pronto.
Sr. Xcoder

2
81 bytes . Las letras mayúsculas y minúsculas coinciden convenientemente cuando se modulan por 32
Arfie

@Ruud Esas son exactamente las cosas de las que estaba hablando en mi comentario, edición.
Sr. Xcoder


8
Estoy esperando que el downvoter explique sus razones.
Sr. Xcoder


4

Brachylog , 15 bytes

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

Pruébalo en línea!

Esto sería 10 bytes: ⊇.ḷ~sẠ&h~hsi no fuera por la restricción poco interesante "las cadenas pueden comenzar con espacios".

Explicación

;Ṣ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 esto es bastante declarativo, esto también es realmente lento.


Bueno, al menos le gana a Jelly! Y, por el lado positivo, no creo que realmente puedas superar esto ...
Erik the Outgolfer

3

MATL , 18 16 15 bytes

Gracias a Mr.Xcoder por señalar un error, ahora corregido

Xz1&)"t@hkd1=?@

Las letras en la salida están separadas por nuevas líneas.

Pruébalo en línea! O verifique todos los casos de prueba (el código de pie de página muestra todas las letras de salida en la misma línea para mayor claridad).

Explicación

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)

Olvidó eliminar los espacios cuando están al comienzo de la cadena: el espacio no es una letra del alfabeto y, por lo tanto, siempre debe eliminarse, incluso si es el comienzo de la cadena .
Sr. Xcoder

@ Mr.Xcoder Gracias! Corregido
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;}

Guardado 2 bytes gracias a @Mr. Xcoder
Guardado 4 bytes gracias a @jkelm.

Pruébalo en línea!


Falla en espacios principales
Skidsdev

@Mayube Woops no vio eso, solucionado.
TheLethalCoder

2
91 bytes . En lenguajes tipo C y Python, (c-1)%32es~-c%32
Sr. Xcoder

1
87 bytes No es necesario reasignar la cadena recortada debido a las comprobaciones en el bucle for
jkelm

2

PHP, 64 + 1 bytes

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

Ejecutar como tubería -nRo probarlo en línea .


Aparte de los trucos habituales: Cuando $calcances Z, ++$cresultados en AA,
y &__mantiene intacta esa longitud; así $nque no coincidirá más $c.




2

Pyth, 21 20 18 bytes

ef&qhThQhxGrT0tyr6

Pruébalo aquí.

Versión de 20 bytes mucho más eficiente:

.U+b?t-CrZ1Creb1kZr6

Pruébalo aquí.

-1 gracias al Sr. Xcoder (indirectamente).


Equivalente: .U+b?tlrreb1rZ1kZrz6(creo). Sin embargo, ese truco me ayudó.
Sr. Xcoder

@ Mr.Xcoder Si eso fuera un equivalente, podría haber guardado un byte .U+b?tlrreb1rZ1kZr6pero, desafortunadamente , r <str> 6significa A.strip(), no eliminar espacios en blanco no iniciales o finales.
Erik the Outgolfer

Oh, sí, no vi que su solución se basara en la eliminación de todos los espacios (la mía no)
Sr. Xcoder

@ Mr.Xcoder Umm, debe eliminar todos los espacios.
Erik the Outgolfer

No, no debería, ya que el espacio tiene un valor ASCII de 32, mientras que todas las letras tienen > 64, y por lo tanto no afecta la funcionalidad. Creo que esto también se aplica a tu respuesta.
Sr. Xcoder

1

Perl 6 , 51 bytes

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

Pruébalo

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
}

Tenga en cuenta que <!before …>es una aserción de ancho cero



1

Japt , 18 17 16 bytes

Guardado 1 byte gracias a @Shaggy

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

¡Pruébelo en línea!

Estaba pensando que esto sería un poco más corto, pero ... Así es la vida ...

Explicación

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.

Más corto que mi parodia de 28 bytes, ¡al menos! : D Parece que puedes reemplazarlo rScon x.
Shaggy

1

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

-10 bytes gracias a TheLethalCoder

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

El recuento de bytes también incluye:

using System.Linq;

Pruébalo en línea!

1 byte más (actualmente) (no más) que TheLethalCoder's, por lo que se publica por diversión. Enfoque diferente, con LINQ.

Esto aprovecha dos características similares a C en C #: una charvariable de caracteres se comporta implícitamente igual que un entero int, y el operador booleano AND &&no ejecuta la operación correcta si la izquierda devuelve a false. Explicación del 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)
           );
}

Elimine el .ToArray()mediante la devolución como un IEnumerable<char>para guardar bytes.
TheLethalCoder

@TheLethalCoder bien, acabo de ver el comentario bajo el desafío. ¡Gracias!
Grzegorz Puławski

1

q / kdb +, 47 45 bytes

Solución:

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

Ejemplos:

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"

Explicación:

Aprovechando el mod 32truco de las soluciones existentes junto con la función de convergencia . Iterar sobre la cadena, si la diferencia entre el último elemento del resultado (por ejemplo, comienza con T"El zorro rojo rápido ...") y el carácter actual es 1 (después de ser mod'd con 32), entonces agregamos esto a el resultado (por lo tanto, tomando por qué tomamos last x), luego vuelve todo a una cadena.

{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

Pruébalo en línea!

¿Cómo?

/$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

Pruébalo en línea! El enlace incluye casos de prueba. Explicación:

 

Eliminar espacios.

^.
$&$&$&¶

Triplique el primer carácter e inserte un separador.

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

Convierta los caracteres segundo y tercero a minúsculas e increméntelos. Convierta este último a mayúsculas. Estos son ahora los personajes de búsqueda.

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

Intenta hacer coincidir cualquiera de los caracteres de búsqueda. Si se encuentra, triplicar la coincidencia, lo que reinicia el ciclo para la próxima búsqueda. De lo contrario, simplemente elimine los caracteres de búsqueda y el resto de la entrada.


0

8vo , 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 ;

Explicación

: 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
;

Ejemplo

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



0

Pyth, 15 bytes

eo,}r0NG_xQhNty

Banco de pruebas

A diferencia de todas las otras respuestas, esto no une la salida, genera todas las subsecuencias de la entrada, y luego les ordena colocar la cadena deseada al final, y la genera.


Creo que debe verificar si la primera letra de la salida es también la primera letra de la entrada. Y creo que el orden inicial es importante.
Erik the Outgolfer

@EriktheOutgolfer Lo siento, ¿estás diciendo que la respuesta es incorrecta? Me aseguro de que la secuencia cuyo primer carácter es el primero en la entrada entre todas las subsecuencias que están en orden alfabético sea la ordenada hasta el final. Vea el caso de prueba comenzando con un espacio.
isaacg

¿Puedes agregar una explicación por favor? Puede que haya entendido mal o algo así ...
Erik the Outgolfer

0

J, solución parcial

Estoy publicando esto para obtener comentarios e ideas para mejorar más que cualquier otra cosa. Funciona, pero no maneja los casos de mayúsculas y espacio, y ya es largo para J.

Primero, un verbo auxiliar diádico que te dice si los argumentos izquierdo y derecho son alfabéticamente adyacentes:

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

A continuación, un verbo que elimina el primer elemento que no forma parte de una línea alfabética a partir del primer elemento:

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

Tenga en cuenta que usamos Adverso ::para devolver el argumento completo sin cambios si no se encuentra un elemento que no sea una raya (es decir, si todo el argumento es una racha alfabética válida).

Finalmente, la solución se da aplicando fhasta la convergencia:

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

Pruébalo en línea!


Y aquí hay una versión analizada fpara facilitar la lectura:

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

Pregunta secundaria : ¿por qué los caracteres del cuadro no se alinean perfectamente cuando se muestran en SO (funcionan en mi consola):

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.