Zredukuj ciąg do fragmentu alfabetu


25

Biorąc pod uwagę niepusty ciąg składający się wyłącznie z małych i wielkich liter alfabetu i spacji ( [a-zA-Z ]), zmniejsz go do fragmentu alfabetu, zaczynając od pierwszego znaku.

Aby zmniejszyć ciąg, zacznij od pierwszego znaku alfabetu, a następnie usuń każdy znak po nim, który nie jest kolejną literą alfabetu. Kontynuuj robienie tego, aż dojdziesz do końca łańcucha.

Na przykład codegolf:

Rozpocznij od c, usuń, oponieważ nie jest to kolejna litera alfabetu.
Zachowaj, dponieważ jest to kolejna litera alfabetu, i zachowaj, eponieważ jest to kolejna litera.
Usunąć g, oi l, i zachować f.

Twój końcowy fragment byłby wtedy cdef

Zasady

  • Kapitalizacja powinna być zachowana, więc CodEgolFspowodowałoby toCdEF
  • Spacja nie jest literą alfabetu, dlatego należy ją zawsze usuwać, nawet jeśli jest to początek ciągu
  • Ze względu na charakter redukcji, pierwszy znak alfabetyczny wejścia zawsze będzie pierwszym znakiem wyjścia.
  • zZjest ostatnią literą alfabetu. Po nim nie ma liter, alfabet się nie zapętla.

Przypadki testowe

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

Punktacja

To jest , więc wygrywa najmniej bajtów w każdym języku !


Z drugiego ostatniego przypadku testowego widzę, że jeśli osiągniemy zZatrzymamy się, prawda?
Pan Xcoder,

@ Mr.Xcoder Poprawnie, patrz ostatni punkt w „Regułach”
Skidsdev

2
Dodaj przypadek testowy ze spacją na początku. Jak:<space>codegolf
Pan Xcoder,

Czy mogę zwrócić tablicę liter wyjściowych?
TheLethalCoder

1
@ Mr.Xcoder tak, możesz
Skidsdev

Odpowiedzi:


12

JavaScript (ES6), 66 79 68 67 bajtów

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

W jaki sposób?

Testowanie kolejnych liter

Ponieważ konwersja dwóch znaków na ich kody ASCII byłaby dość długą operacją w JS, zamiast tego używamy następującej formuły:

~parseInt(b + a, 36) % 37

Pod warunkiem, że oba i b są , powyższe wyrażenie jest równe wtedy i tylko wtedy, gdy i b są kolejnymi literami (tj kolejne cyfry w bazie 36), bez względu na przypadek bohaterów.[a-zA-Z ]0

Na przykład:

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

Sformatowane i skomentowane

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

Przypadki testowe


7

Python 2 , 69 bajtów

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

Wypróbuj online!

Prosta redukcja ciągu. Po prostu łączymy następny znak wtedy i tylko wtedy (ord(y)-ord(x[~0]))%32==1. Bardzo brzydka kontrola - jestem pewien, że można ją poprawić, ale nie jestem pewien jak!


Sprytne rozwiązanie! Szkoda, że ​​to tylko Python 2: P
Mr. Xcoder

Możesz uczynić go kompatybilnym z Python 3 z from functools import*.
całkowicie ludzki,

1
@ThomasWard totalnie ludzki mówił innym, jak uczynić go kompatybilnym z Python 3. Btw, import functools as fi f.jest znacznie dłuższy niż from functools import*na pewno, nawet użyty raz. Zobacz ten wątek, aby uzyskać więcej informacji.
Pan Xcoder,

7

Python 3 , 75 85 84 91 81 77 75 bajtów

Myślę, że jest tak krótki, jak to tylko możliwe w Pythonie 3 . Można go skrócić o kilka bajtów w Pythonie 2, jak pokazano w przesłaniu Syzyfa .

  • EDYCJA: +10 do naprawy błędu
  • EDYCJA: -1 poprzez naprawienie kolejnego błędu
  • EDYCJA: +7 za naprawienie kolejnego błędu
  • EDYCJA: -10 bajtów przy pomocy @Ruud
  • EDYCJA: -4 bajty, ponieważ OP umożliwiło nam wyprowadzenie liter oddzielonych znakiem nowej linii
  • EDYCJA: -2 bajty dzięki @Ruud , powrót do pierwotnej liczby bajtów!
s=input().strip();k=0
for i in s:
 if(ord(i)-ord(s[0]))%32==k:k+=1;print(i)

Wypróbuj online!


Mam pomysły na ulepszenia, wkrótce gra w golfa na urządzeniach mobilnych.
Pan Xcoder,

2
81 bajtów . Wielkie i małe litery wygodnie pasują, gdy są modulowane przez 32
Arfie

@Ruud To są dokładnie te rzeczy, o których mówiłem w moim komentarzu do edycji.
Pan Xcoder,


8
Czekam, aż downvoter wyjaśni swoje powody.
Pan Xcoder,


4

Brachylog , 15 bajtów

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

Wypróbuj online!

Będzie to 10 bajtów: ⊇.ḷ~sẠ&h~h gdyby nie dość nieciekawe ograniczenie „łańcuchy mogą zaczynać się spacjami”.

Wyjaśnienie

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

Ponieważ jest to dość deklaratywne, jest to również bardzo powolne.


Cóż, przynajmniej bije Galaretkę! I na plus, nie sądzę, że naprawdę możesz wygrać z tym golfem ...
Erik the Outgolfer

3

MATL , 18 16 15 bajtów

Dzięki Mr.Xcoder za wskazanie błędu, teraz poprawionego

Xz1&)"t@hkd1=?@

Litery na wyjściu są oddzielone znakami nowej linii.

Wypróbuj online!Lub sprawdź wszystkie przypadki testowe (dla zachowania przejrzystości kod stopki wyświetla wszystkie litery wyjściowe w tym samym wierszu).

Wyjaśnienie

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)

Zapomniałeś usunąć spacje, gdy znajdują się na początku łańcucha: Spacja nie jest literą alfabetu i dlatego zawsze powinna być usuwana, nawet jeśli jest to początek łańcucha .
Pan Xcoder,

@ Mr.Xcoder Thanks! Poprawiono
Luis Mendo,


2

C # (mono) , 129 107 93 91 87 bajtów

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

Zaoszczędź 2 bajty dzięki @Mr. Xcoder.
Zaoszczędź 4 bajty dzięki @jkelm.

Wypróbuj online!


Nie
działa

@Mayube Woops tego nie widział, naprawiono.
TheLethalCoder

2
91 bajtów . W językach podobnych do C i Pythonie (c-1)%32jest~-c%32
Pan Xcoder

1
87 bajtów Nie trzeba ponownie przypisywać przyciętego ciągu ze względu na kontrole w pętli for
jkelm

2

PHP, 64 + 1 bajtów

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

Uruchom jako potok z -nRlub spróbuj online .


Oprócz typowych sztuczek: Kiedy $cdotrze Z, ++$cpowoduje AA,
i &__przechowuje że długość nietknięty; więc nie $nbędzie już pasować $c.




2

Pyth, 21 20 18 bajtów

ef&qhThQhxGrT0tyr6

Wypróbuj tutaj.

Znacznie wydajniejsza 20-bajtowa wersja:

.U+b?t-CrZ1Creb1kZr6

Wypróbuj tutaj.

-1 dzięki Mr. Xcoder (pośrednio).


Odpowiednik: .U+b?tlrreb1rZ1kZrz6(myślę). Ta sztuczka mi jednak pomogła.
Pan Xcoder,

@ Mr.Xcoder Gdyby to był odpowiednik, mógłbym zaoszczędzić bajt, .U+b?tlrreb1rZ1kZr6ale niestety r <str> 6oznacza to A.strip(), że nie usuwam nie wiodących lub końcowych białych znaków.
Erik the Outgolfer,

O tak, nie widziałem, żeby twoje rozwiązanie
opierało się na usuwaniu

@ Mr.Xcoder Umm, powinieneś usunąć wszystkie spacje.
Erik the Outgolfer,

Nie, nie powinienem, ponieważ spacja ma wartość ASCII 32, podczas gdy wszystkie litery mają > 64, a zatem nie wpływa na funkcjonalność. Myślę, że dotyczy to również twojej odpowiedzi.
Pan Xcoder,

1

Perl 6 , 51 bajtów

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

Sprawdź to

Rozszerzony:

{  # 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
}

Zauważ, że <!before …>jest to stwierdzenie o zerowej szerokości



1

Japt , 18 17 16 bajtów

Zaoszczędzono 1 bajt dzięki @Shaggy

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

Przetestuj online!

Myślałem, że to będzie trochę krótsze, ale ... Takie jest życie ...

Wyjaśnienie

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.

Przynajmniej krótszy niż moja 28-bajtowa trawestacja! : D Wygląda na to można zastąpić rSz x.
Kudłaty

1

C # (.NET Core) , 70 60 + 18 bajtów

-10 bajtów dzięki TheLethalCoder

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

Liczba bajtów obejmuje również:

using System.Linq;

Wypróbuj online!

1 bajt dłużej (obecnie) (już nie) niż TheLethalCoder, więc publikowanie w celach rozrywkowych. Inne podejście z LINQ.

Wykorzystuje to dwie funkcje podobne do C w C # - charzmienna znakowa domyślnie zachowuje się tak samo jak liczba całkowita int, a operator logiczny AND &&nie wykonuje właściwej operacji, jeśli left zwraca a false. Objaśnienie kodu:

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)
           );
}

Usuń .ToArray(), zwracając jako, IEnumerable<char>aby zapisać bajty.
TheLethalCoder

@TheLethalCoder racja, właśnie widziałem komentarz w ramach wyzwania. Dziękuję Ci!
Grzegorz Puławski

1

q / kdb +, 47 45 bajtów

Rozwiązanie:

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

Przykłady:

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"

Wyjaśnienie:

Wykorzystanie mod 32sztuczki z istniejących rozwiązań wraz z funkcją zbieżności . Iteruj po łańcuchu, jeśli różnica między ostatnim elementem wyniku (np. Zaczyna się Tod „Szybki czerwony lis ...”) a bieżącym znakiem wynosi 1 (po byciu mod32 d), dodajemy to do wynik (stąd przyjmujemy, dlaczego bierzemy last x), a następnie rzuć wszystko z powrotem do łańcucha.

{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 bajtów

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

Wypróbuj online!

W jaki sposób?

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

Siatkówka , 76 bajtów

 

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

Wypróbuj online! Link zawiera przypadki testowe. Wyjaśnienie:

 

Usuń spacje.

^.
$&$&$&¶

Potrój trzykrotnie pierwszy znak i wstaw separator.

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

Konwertuj drugi i trzeci znak na małe litery i zwiększaj je. Konwertuj te ostatnie na wielkie litery. To są teraz znaki wyszukiwania.

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

Spróbuj dopasować jeden z wyszukiwanych znaków. Jeśli zostanie znaleziony, trzykrotnie dopasuj, co spowoduje ponowne uruchomienie pętli do następnego wyszukiwania. W przeciwnym razie po prostu usuń wyszukiwane znaki i resztę danych wejściowych.


0

8th , 114 bajtów

Kod

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

Wyjaśnienie

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

Przykład

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



0

Pyth, 15 bajtów

eo,}r0NG_xQhNty

Zestaw testowy

W przeciwieństwie do wszystkich innych odpowiedzi, nie skleja to danych wyjściowych, generuje wszystkie podsekwencje danych wejściowych, a następnie nakazuje im umieszczenie żądanego ciągu na końcu i wysyła go.


Myślę, że musisz sprawdzić, czy pierwsza litera wyjścia jest również pierwszą literą wejścia. I myślę, że pierwsze zamówienie ma znaczenie.
Erik the Outgolfer,

@EriktheOutgolfer Przepraszamy, czy mówisz, że odpowiedź jest nieprawidłowa? Upewniam się, że sekwencja, której pierwszy znak jest najwcześniejszy z wszystkich podsekwencji alfabetycznych, jest posortowana do końca. Zobacz przypadek testowy zaczynający się od spacji.
isaacg

Czy możesz dodać wyjaśnienie? Być może źle zrozumiałem lub coś ...
Erik the Outgolfer

0

J, częściowe rozwiązanie

Publikuję to w celu uzyskania opinii i pomysłów na ulepszenia bardziej niż cokolwiek innego. Działa, ale nie obsługuje wielkości liter i spacji na krawędziach i jest już długi dla J.

Najpierw dyadyczny czasownik pomocniczy, który informuje, czy lewy i prawy argument znajdują się w kolejności alfabetycznej:

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

Następnie czasownik, który usuwa pierwszy element, który nie jest częścią alfabetu, zaczynając od pierwszego elementu:

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

Zauważ, że używamy Adverse, ::aby zwrócić cały argument bez zmian, jeśli nie znaleziono elementu niepasującego (tj. Jeśli cały argument jest prawidłową pasmą alfabetyczną).

Wreszcie, rozwiązanie jest podane przez zastosowanie faż do konwergencji:

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

Wypróbuj online!


A oto parsowana wersja fdla łatwiejszego czytania:

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

Pytanie poboczne : dlaczego znaki pola nie są idealnie wyrównane, gdy są wyświetlane na SO (działają w mojej konsoli):

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.