Уменьшить строку до фрагмента алфавита


25

Учитывая непустую строку, состоящую только из строчных и заглавных буквенных символов и пробелов ( [a-zA-Z ]), уменьшите ее до фрагмента алфавита, начиная с первого символа.

Чтобы уменьшить строку, начните с первого алфавитного символа, затем удалите каждый символ после него, который не является следующей буквой алфавита. Продолжайте делать это, пока не дойдете до конца строки.

Например codegolf:

Начните с cудаления, oпоскольку это не следующая буква алфавита.
Продолжайте , dкак это является следующей буквой алфавита, и сохранить , eкак это следующая буква тоже.
Удалить g, oи l, и сохранить f.

Ваш последний фрагмент будет тогда cdef

правила

  • Капитализация должна быть сохранена, поэтому CodEgolFприведет кCdEF
  • Пробел не является буквой алфавита, и поэтому всегда должен быть удален, даже если это начало строки
  • Из-за характера сокращения первый алфавитный символ ввода всегда будет первым символом вывода.
  • zZэто последняя буква алфавита. После него букв нет, алфавит не зацикливается.

Тестовые случаи

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

счет

Это , поэтому выигрывает меньшее количество байтов на каждом языке !


Из второго последнего теста я вижу, что если мы дойдем, zмы просто остановимся, верно?
Мистер Кскодер

@ Mr.Xcoder Правильно, см. Последний пункт в разделе «Правила»
Skidsdev

2
Пожалуйста, добавьте контрольный пример с пробелом в начале. Как:<space>codegolf
г-н Xcoder

Могу ли я вернуть массив выходных букв?
TheLethalCoder

1
@ Mr.Xcoder да, вы можете
Скидсдев

Ответы:


12

JavaScript (ES6), 66 79 68 67 байт

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

Как?

Тестирование последовательных писем

Поскольку преобразование двух символов в их ASCII-коды было бы довольно длительной операцией в JS, вместо этого мы используем следующую формулу:

~parseInt(b + a, 36) % 37

При условии, что оба a и b находятся в [a-zA-Z ], приведенное выше выражение равно, 0если и только если a и b являются последовательными буквами (то есть последовательными цифрами в базе 36), независимо от регистра символов.

Например:

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

Отформатировано и прокомментировано

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

Контрольные примеры


7

Python 2 , 69 байт

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

Попробуйте онлайн!

Простое сокращение строки. Мы просто объединяем следующий символ тогда и только тогда, когда (ord(y)-ord(x[~0]))%32==1. Очень некрасивая проверка - я уверен, что это можно улучшить, но я не уверен, как!


Умное решение! Жаль, что это только на Python 2: P
Mr. Xcoder

Вы можете сделать его совместимым с Python 3 с помощью from functools import*.
полностью человек

1
@ThomasWard полностью человек просто рассказывал другим, как сделать его совместимым с Python 3. Кстати, import functools as fи f.намного дольше, чем from functools import*наверняка, даже используется один раз. Смотрите эту тему для получения дополнительной информации.
Мистер Кскодер

7

Python 3 , 75 85 84 91 81 77 75 байтов

Я думаю, что это настолько короткий, насколько это возможно в Python 3 . Это может быть сокращено на несколько байтов в Python 2, как показано в представлении Сизифа .

  • РЕДАКТИРОВАТЬ: +10 для исправления ошибки
  • РЕДАКТИРОВАТЬ: -1, исправляя другую ошибку
  • РЕДАКТИРОВАТЬ: +7 для исправления еще одной ошибки
  • РЕДАКТИРОВАТЬ: -10 байт с помощью @Ruud
  • РЕДАКТИРОВАТЬ: -4 байта, так как ОП позволил нам вывести буквы, разделенные новой строкой
  • РЕДАКТИРОВАТЬ: -2 байта благодаря @Ruud , вернуться к исходному количеству байтов!
s=input().strip();k=0
for i in s:
 if(ord(i)-ord(s[0]))%32==k:k+=1;print(i)

Попробуйте онлайн!


У меня есть идеи по улучшению, игра в гольф в скором времени.
г-н Xcoder

2
81 байт . Прописные и строчные буквы удобно совпадают при модуляции 32
Арфи

@Ruud Это именно то, о чем я говорил в своем комментарии, редактировании.
г-н Xcoder


8
Я жду, чтобы downvoter объяснил свои причины.
г-н Xcoder


4

Брахилог , 15 байт

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

Попробуйте онлайн!

Это было бы 10 байт: ⊇.ḷ~sẠ&h~hесли бы не было довольно неинтересного ограничения «строки могут начинаться с пробелов».

объяснение

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

Поскольку это довольно декларативно, это также очень медленно.


Ну, по крайней мере, это лучше, чем Jelly! И, с другой стороны, я не думаю, что вы действительно можете переиграть это ...
Эрик Outgolfer

3

MATL , 18 16 15 байт

Спасибо Mr.Xcoder за указание на ошибку, теперь исправлена

Xz1&)"t@hkd1=?@

Буквы в выводе разделены переводом строки.

Попробуйте онлайн! Или проверьте все контрольные примеры (код нижнего колонтитула отображает все выходные буквы в одной строке для ясности).

объяснение

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)

Вы забыли удалить пробелы, когда они находятся в начале строки: пробел не является буквой алфавита и, следовательно, всегда должен быть удален, даже если это начало строки .
Мистер Кскодер

@ Mr.Xcoder Спасибо! Исправлено
Луис Мендо


2

C # (Mono) , 129 107 93 91 87 байтов

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

Сохранено 2 байта благодаря @Mr. Xcoder.
Сохранено 4 байта благодаря @jkelm.

Попробуйте онлайн!


Сбой на ведущих местах
Скидсдев

@ Mayube Woops этого не видел, исправлено.
TheLethalCoder

2
91 байт . На C-подобных языках и Python, (c-1)%32это~-c%32
Mr. Xcoder

1
87 байт Вам не нужно переназначать обрезанную строку из-за проверок в цикле for
jkelm

2

PHP, 64 + 1 байт

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

Запустите как трубу с -nRили попробуйте онлайн .


Помимо обычных трюков: Когда $cдостигает Z, ++$cприводит AA,
и &__держится , что длина нетронутым; так $nбольше не будет совпадать $c.



2

Haskell, 106 105 97 байт

import Data.Char
import Data.List
z=ord.toUpper
a%b|z a+1==z b=b|0<3=a
nub.scanl1(%).filter(>' ')

Я пытался использовать fromEnum+ char арифметику вместо импорта Data.Char, но это оказалось длиннее ...

Сохранено 8 байтов благодаря H.PWiz!

Попробуйте онлайн.



Или 100 байтов сData.List
H.PWiz

@ H.PWiz Отлично! Благодарность!
Кристиан Лупаску

2

Pyth, 21 20 18 байт

ef&qhThQhxGrT0tyr6

Попробуй это здесь.

Более эффективная 20-байтовая версия:

.U+b?t-CrZ1Creb1kZr6

Попробуй это здесь.

-1 спасибо мистеру Xcoder (косвенно).


Эквивалент: .U+b?tlrreb1rZ1kZrz6(я думаю). Этот трюк помог мне, хотя.
г-н Xcoder

@ Mr.Xcoder Если бы это был эквивалент, я мог бы сэкономить байт, .U+b?tlrreb1rZ1kZr6но, к сожалению, это r <str> 6означает A.strip(), что я не удаляю пробелы без начальных и конечных символов .
Эрик Outgolfer

О да, я не видел, чтобы ваше решение основывалось на удалении всех пробелов (мое - нет)
г-н Xcoder

@ Mr.Xcoder Хмм, вы должны удалить все пробелы.
Эрик Outgolfer

Нет, я не должен, так как пробел имеет значение ASCII 32, тогда как все буквы имеют > 64, и, следовательно, не влияет на функциональность. Я думаю, что это относится и к вашему ответу.
г-н Xcoder

1

Perl 6 , 51 байт

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

Попробуй это

Expanded:

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

Обратите внимание, что <!before …>утверждение нулевой ширины



1

Japt , 18 17 16 байтов

Сохранено 1 байт благодаря @Shaggy

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

Проверьте это онлайн!

Думал, что это будет немного короче, но ... Такова жизнь ...

объяснение

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.

Короче, чем моя 28-байтовая пародия, по крайней мере! : D Похоже, вы можете заменить rSна x.
Лохматый

1

C # (.NET Core) , 70 60 + 18 байт

-10 байт благодаря TheLethalCoder

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

Количество байтов также включает в себя:

using System.Linq;

Попробуйте онлайн!

На 1 байт длиннее (в настоящее время) (не больше), чем в TheLethalCoder, поэтому публикация ради интереса. Другой подход, с LINQ.

Это позволяет использовать две C-подобные функции в C # - символьная charпеременная неявно ведет себя так же, как целое число int, и логический оператор AND &&не выполняет правую операцию, если left возвращает a false. Объяснение кода:

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

Удалите .ToArray(), возвращая как IEnumerable<char>для сохранения байтов.
TheLethalCoder

@TheLethalCoder правильно, я только что увидел комментарий под вопросом. Спасибо!
Гжегож Пулавский

1

q / kdb +, 47 45 байт

Решение:

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

Примеры:

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"

Объяснение:

Используя mod 32трюк из существующих решений вместе с функцией сходятся . Выполните итерацию по строке, если разница между последним элементом результата (например, начинается с T«Быстрая красная лиса ...») и текущим символом равна 1 (после того, как mod'd с 32), то мы добавим это к результат (следовательно, принимая, почему мы берем last x), затем приведем все обратно к строке.

{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 байт

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

Попробуйте онлайн!

Как?

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

Сетчатка , 76 байт

 

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

Попробуйте онлайн!Ссылка включает в себя тестовые случаи. Объяснение:

 

Удалить пробелы.

^.
$&$&$&¶

Тройной первый символ и вставьте разделитель.

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

Преобразуйте второй и третий символы в нижний регистр и увеличивайте их. Преобразовать последний в верхний регистр. Теперь это поисковые символы.

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

Попробуйте сопоставить любой из символов поиска. Если найдено, то дублируйте совпадение, что перезапускает цикл для следующего поиска. В противном случае просто удалите символы поиска и оставшуюся часть ввода.


0

восьмых , 114 байт

Код

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

объяснение

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

пример

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



0

Pyth, 15 байт

eo,}r0NG_xQhNty

Тестирование

В отличие от всех других ответов, это не склеивает вывод, он генерирует все подпоследовательности ввода, а затем приказывает им поместить желаемую строку в конец и выводит ее.


Я думаю, что вы должны проверить, является ли первая буква вывода также первой буквой ввода. И я думаю, что первоначальный порядок имеет значение.
Эрик Outgolfer

@EriktheOutgolfer Извините, вы говорите, что ответ неправильный? Я удостоверяюсь, что последовательность, первый символ которой является самым ранним на входе среди всех подпоследовательностей в алфавитном порядке, является той, которая отсортирована до конца. Смотрите тестовый пример, начинающийся с пробела.
Исаак

Можете ли вы добавить объяснение, пожалуйста? Я, возможно, неправильно понял или что-то ...
Эрик Outgolfer

0

J, частичное решение

Я публикую это для обратной связи и идей для улучшения больше всего на свете. Это работает, но не обрабатывает случаи с заглавными буквами и пробелами, и уже давно для J.

Сначала диадический вспомогательный глагол, который говорит вам, что левый и правый аргументы расположены в алфавитном порядке:

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

Далее глагол, который удаляет первый элемент, который не является частью буквенной полосы, начиная с первого элемента:

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

Обратите внимание, что мы используем неблагоприятные :: чтобы вернуть весь аргумент без изменений, если не найден нестрочный элемент (т. Е. Если весь аргумент является допустимой буквенной строкой).

Наконец, решение дается путем применения fдо сходимости:

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

Попробуйте онлайн!


А вот разобранная версия fдля удобства чтения:

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

Дополнительный вопрос : почему символы ячеек не выровнены идеально при отображении на SO (они работают в моей консоли):

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.