Найти первое слово, начинающееся с каждой буквы


25

По заданной строке найдите первое слово, начинающееся с каждой буквы (без учета регистра).

Образец

Использование в Ferulas flourish in gorgeous gardens.качестве входных данных:

"Ferulas flourish in gorgeous gardens."
 ^^^^^^^          ^^ ^^^^^^^^
 |                |  |
 |                |  --> is the first word starting with `g`
 |                --> is the first word starting with `i`
 --> is the first word starting with `f`

Затем выходные данные для этого образца должны быть совпадающими словами, соединенными одним пробелом:

"Ferulas in gorgeous"

Вызов

И ввод, и вывод должны быть строковым представлением или ближайшей альтернативой на вашем языке.

Программа или функция разрешены.

Вы можете рассмотреть слово, по меньшей мере , одного из: lowercase or uppercase letters, digits, underscore.

Это , самый короткий ответ в байтах выигрывает.

Другие образцы:

input: "Take all first words for each letter... this is a test"
output: "Take all first words each letter is"

input: "Look ^_^ .... There are 3 little dogs :)"
output: "Look _ There are 3 dogs"

input: "...maybe some day 1 plus 2 plus 20 could result in 3"
output: "maybe some day 1 plus 2 could result in 3"

Разрешены ли конечные / начальные пробелы? <s> Можно ли предположить, что слова разделены одним пробелом в исходной строке? </ s>
Qwertiy

Я понял это из примеров, так что в комментарии есть <s> </ s>. А как насчет пробелов?
Qwertiy

Ответы:


17

Сетчатка , 28 байт:

M! I` \ Ь (\ ш) (? <! \ Ь \ 1. +) \ Ш *
¶
 
  • M! - Сопоставьте каждую работу и напечатайте все слова, разделенные переводами.
  • i - Игнорировать дело.
  • \b(\w) - захватить первую букву каждого слова
  • (?<!\b\1.+)- После сопоставления буквы проверьте, не было ли предыдущего слова, начинающегося с той же буквы. \1.+обеспечивает как минимум два символа, поэтому мы пропускаем текущее слово.
  • \w*- соответствовать остальной части слова.
    Вышеуказанное соответствует только словам - все остальные символы удаляются.
  • ¶\n - Заменить символы новой строки пробелами.

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


9

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

i` \ Ъ ((\ ш) \ ш *) \ Ъ (? <= \ Ъ \ 2 \ ш * \ Ъ +.)

\ W +
 
^ | $

Просто использует одно регулярное выражение для удаления более поздних слов, начинающихся с того же \wсимвола (без учета регистра с iопцией), преобразует серии \Wв один пробел, а затем удаляет все пробелы в начале и в конце.

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

Изменить: см . Ответ @ Kobi для более короткой версии, используяM!`


Черт возьми, едва победил меня! Я не мог понять взгляд сзади, хотя.
GamrCorps

3
Я добавил еще один ответ Retina - я думаю, что все в порядке, если они достаточно разные (основная концепция, конечно, похожа).
Коби

1
@Kobi Это намного лучше, так что я рад это видеть :) Заставляет меня понять, сколько еще мне нужно узнать о параметрах линии Retina, а что нет.
Sp3000

Не могли бы вы сделать это, чтобы сохранить несколько байтов? i` \b((\w)\w*)\b(?<=\b\2\w*\b.+)(пробел перед первым \b) Строки после этого не нужны?
Утренняя монахиня

@KennyLau К сожалению, я не думаю, что это работает, потому что слова не обязательно разделяются пробелами, напримерa...a -> a
Sp3000

9

JavaScript (ES6), 73 71 байт

s=>s.match(u=/\w+/g).filter(w=>u[n=parseInt(w[0],36)]?0:u[n]=1).join` `

Сохранено 2 байта благодаря @ edc65!

Тест

var solution = s=>s.match(u=/\w+/g).filter(w=>u[n=parseInt(w[0],36)]?0:u[n]=1).join` `;
var testCases = [
  "Ferulas flourish in gorgeous gardens.",
  "Take all first words for each letter... this is a test",
  "Look ^_^ .... There are 3 little dogs :)",
  "...maybe some day 1 plus 2 plus 20 could result in 3"
];
document.write("<pre>"+testCases.map(t=>t+"\n"+solution(t)).join("\n\n")+"</pre>");


Используя parseInt("_",36) = NaN? Богохульство!
Sp3000

1
Интересный факт: это работает @ Sp3000
edc65

Использование u = regexp действительно умно. Сохранить 2 байтаs=>s.match(u=/\w+/g).filter(w=>u[w=parseInt(w[0],36)]?0:u[w]=1).join' '
edc65

@ edc65 Спасибо. На самом деле очень удобно, что на одну цифру base-36 есть 37 возможных выходов.
user81655

7

Pyth, 23 байта

J:z"\w+"1jdxDJhM.grhk0J

Попробуйте онлайн: демонстрация или тестовый набор

J:z"\w+"1находит все слова во входных данных с помощью регулярных выражений \w+и сохраняет их в J.

.grhk0Jгруппирует слова по их первой строчной букве, hMберет первое из каждой группы, xDJсортирует эти слова по индексу во входной строке и jdставит пробелы между ними.


4

Perl 6, 39 байт

{.words.grep({!%.{.substr(0,1).lc}++})}

1
42 байта, которые фиксируют слова, которые должны соответствовать, \w+и играют substrроль в гольфе
Джо Кинг,

3

C 142 132 122 байта

На 10 байт легче благодаря @tucuxi!

b[200],k;main(c){for(;~c;isalnum(c)|c==95?k&2?:(k|=!b[c|32]++?k&1?putchar(32):0,7:2),k&4?putchar(c):0:(k&=1))c=getchar();}

Печатает завершающий пробел после последнего выходного слова.


1
Вы можете бриться проверяете c>47и c<58используя isalnumвместоisalpha
белого дельфина

3

MATL , 23 байта

'\w+'XXtck1Z)t!=XRa~)Zc

Это заимствует идею Якуба использовать регулярное выражение для удаления нежелательных символов и разделения одновременно.

Ввод - это строка, заключенная в одинарные кавычки.

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

объяснение

'\w+'XX  % find words that match this regexp. Gives a cell array
t        % duplicate
c        % convert into 2D char array, right-padded with spaces
k        % make lowercase
1Z)      % get first column (starting letter of each word)
t!=      % duplicate, transpose, test for equality: all combinations  
XR       % set diagonal and below to 0
a~       % true for columns that contain all zeros       
)        % use as a logical index (filter) of words to keep from the original cell array
Zc       % join those words by spaces

2

Vim 57 нажатий клавиш

:s/[^a-zA-Z_ ]//g<cr>A <cr>ylwv$:s/\%V\c<c-v><c-r>"\h* //eg<c-v><cr>@q<esc>0"qDk@q

Объяснение:

:s/[^a-zA-Z_ ]//g                                 #Remove all invalid chars.
A <cr>                                            #Enter insert mode, and enter 
                                                  #a space and a newline at the end
ylwv$:s/\\c%V<c-v><c-r>"\h* //eg<c-v><cr>@q<esc>  #Enter all of this text on the 
                                                  #next line

0                                                 #Go to the beginning of the line
"qD                                               #Delete this line into register
                                                  #"q"
k@q                                               #Run "q" as a macro  

#Macro
ylw                                               #Yank a single letter
   v$                                             #Visual selection to end of line
     :s/                                          #Substitute regex
       \%V\c                                      #Only apply to the selection and 
                                                  #ignore case
            <c-v><c-r>"                           #Enter the yanked letter
                       \h*                        #All "Head of word" chars
                                                  #And a space
                           //                     #Replace with an empty string
                             eg                   #Continue the macro if not found
                                                  #Apply to all matches
                               <c-v><cr>          #Enter a <CR> literal
                                        @q<esc>   #Recursively call the macro

Я действительно разочарован тем, как долго этот. В символах «инвалидные» (все , кроме a-z, A-Z, _и пространство) действительно бросил меня. Я уверен, что есть лучший способ сделать это:

:s/[^a-zA-Z_ ]//g

Так как \hсоответствует всему тому, что ожидается для пробела, но я не могу понять, как поместить метачар в диапазон. Если у кого-то есть советы, я бы хотел их услышать.


3
почему a-zA-Z_и нет \w? цифры действительны
edc65

2

Юлия, 165 155 151 129 102 байта

g(s,d=[])=join(filter(i->i!=0,[(c=lcfirst(w)[1])∈d?0:(d=[d;c];w)for w=split(s,r"\W",keep=1<0)])," ")

Это функция, которая принимает строку и возвращает строку.

Ungolfed:

function g(s, d=[])
    # Split the string into an array on unwanted characters, then for
    # each word, if the first letter has been encountered, populate
    # this element of the array with 0, otherwise note the first letter
    # and use the word. This results in an array of words and zeros.
    x = [(c = lcfirst(w)[1])  d ? 0 : (d = [d; c]; w) for w = split(s, r"\W", keep=1<0)]

    # Remove the zeros, keeping only the words. Note that this works
    # even if the word is the string "0" since 0 != "0".
    z = filter(i -> i != 0, x)

    # Join into a string and return
    return join(z, " ")
end

Сохранено 53 байта с помощью Sp3000!



2

C # (LINQPAD) - 136 128 байт

var w=Util.ReadLine().Split(' ');string.Join(" ",w.Select(s=>w.First(f=>Regex.IsMatch(""+f[0],"(?i)"+s[0]))).Distinct()).Dump();

2

05AB1E , 40 байт

Код:

94L32+çJžj-DU-ð¡""Kvy¬Xsl©åï>iX®«Uy}\}ðý

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

Объяснение:

Сначала мы генерируем все символы, которые должны быть удалены из входной строки, используя 94L32+ç( Попробуйте здесь ). Мы соединяем эту строку, используя Jи удаляем, [a-zA-Z0-9_]которая хранится в žj ( попробуйте здесь ). Мы удаляем все символы из второй строки из первой строки, что оставляет нас:

!"#$%&'()*+,-./:;<=>?@[\]^`{|}~

Это также можно проверить здесь . Мы Dуточняем это и сохраняем Xс U-командой. Затем мы удаляем все символы из этой строки из ввода. Затем мы разделяем пробелы, используя ð¡и удаляем все пустые строки (используя ""K). Теперь у нас есть это .

Это чистая версия ввода, с которой мы будем работать. Мы наносим на карту каждый элемент, используя v. Это использует yв качестве строковой переменной. Мы берем первый символ строки с помощью ¬и нажимаем X, который содержит строку со всеми запрещенными символами ( !"#$%&'()*+,-./:;<=>?@[\]^`{|}~). Мы проверяем, есть ли в этой lстроке версия первого символа owercase (которая также будет ©указана в регистре), используя å. Охватывается этой частью: ï>iесли первая строка не существует в строке запрещенных символов ( X), мы добавляем эту букву в список запрещенных символов (сделано с помощью X®«U) и помещаем yповерх стека.

Наконец, когда строки фильтруются, мы соединяем стек с помощью пробелов ðý.


1
... объяснение? :-)
Луис Мендо

@LuisMendo Спасибо, что напомнили мне! Готово :)
Аднан

2

PHP

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

С функцией оболочки, 89 байт

function f($s){foreach(preg_split('/\W/',$s)as$w)$c[lcfirst($w)[0]]++?:$v.=" $w";echo$v;}

Без оболочки функции (требуется предварительное объявление $ s), 73 байта

foreach(preg_split('/\W/',$s)as$w)$c[lcfirst($w)[0]]++?:$v.=" $w";echo$v;

Объяснение:

foreach(preg_split('/\W/',$s)as$w)$c[lcfirst($w)[0]]++?:$v.=" $w";echo$v;
        preg_split('/\w/',$s)                                             Break input on all non-word characters
foreach(                     as$w)                                        Loop through each 'word'
                                     lcfirst($w)[0]                       Take the first letter of the lowercase version of the word
                                  $c[              ]++?:                  Increment an array element with a key of that letter after checking if it's false-y (0)
                                                        $v.=" $w";        Add the word if the letter wasn't found (if the previous condition evaluated to false)
                                                                  echo$v; Print the new string to screen.

Мое единственное сожаление в том, что я не смог найти более быстрый способ проверки / преобразования регистра.


2

Python, 103 байта

import re
lambda s,d=[]:[w for w in re.findall("\w+",s)if(d.append(w.lower()[0])or d[-1])not in d[:-1]]

1

Луа, 172 байта

Это закончилось намного дольше, чем я хотел ...

t={}(...):gsub("[%w_]+",function(w)b=nil for i=1,#t
do b=t[i]:sub(1,1):lower()==w:sub(1,1):lower()and 1 or b
end t[#t+1]=not b and w or nil end)print(table.concat(t," "))

Ungolfed

t={}                           -- initialise the accepted words list
(...):gsub("[%w_]+",function(w)-- iterate over each group of alphanumericals and underscores
  b=nil                        -- initialise b (boolean->do we have this letter or not)
  for i=1,#t                   -- iterate over t
  do
    b=t[i]:sub(1,1):lower()    -- compare the first char of t's i word
       ==w:sub(1,1):lower()    -- and the first char of the current word
           and 1               -- if they are equals, set b to 1
           or b                -- else, don't change it
  end
  t[#t+1]=not b and w or nil   -- insert w into t if b isn't set
end)

print(table.concat(t," "))     -- print the content of t separated by spaces

1

Серьезно, 43 байта

6╙¬▀'_+,;)-@s`;0@Eùk`M┬i;╗;lrZ`i@╜í=`M@░' j

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

Отсутствие возможностей регулярных выражений сделало это намного сложнее, чем нужно.

Объяснение:

6╙¬▀'_+,;)-@s`;0@Eùk`M┬i;╗;lrZ`i@╜í=`M@░' j
6╙¬▀                                         push digits in base 62 (uppercase and lowercase letters and numbers)
    '_+                                      prepend underscore
       ,;)                                   push two copies of input, move one to bottom of stack
          -                                  get all characters in input that are not letters, numbers, or underscores
           @s                                split input on all occurrences of non-word characters
             `;0@Eùk`M                       for each word: push the first letter (lowercased)
                      ┬i                     transpose and flatten (TOS is list of first letters, then list of words)
                        ;╗                   push a copy of the first letters list to register 0
                          ;lrZ               zip the list of first letters with their positions in the list
                              `i@╜í=`M       for each first letter: push 1 if that is the first time the letter has been encountered (first index of the letter matches its own index) else 0
                                      @░     filter words (take words where corresponding element in the previous list is truthy)
                                        ' j  join on spaces

1

Ruby 76 байт

s;f={};s.scan(/(([\w])[\w]*)/).map{|h,i|f[j=i.upcase]?nil:(f[j]=!p; h)}.compact.*' '

Или с определением метода 88 байтов

def m s;f={};(s.scan(/((\w)\w*)/).map{|h,i|f[j=i.upcase]?nil:(f[j]=1; h)}-[p]).*' ';end

Неуправляемый и с юнит-тестом:

def m_long(s)
  #found  - Hash with already found initials
  f={}
  #h=hit, i=initial, j=i[0].downcase
  s.scan(/(([\w\d])[\w\d]*)/).map{|h,i| 
    f[j=i.upcase] ? nil : (f[j] = true; h)
  }.compact.join(' ')
end
#true == !p
#~ def m(s)
  #~ f={};s.scan(/(([\w\d])[\w\d]*)/).map{|h,i|f[j=i.upcase]?nil:(f[j]=!p; h)}.compact.join' '
#~ end
def m s;f={};s.scan(/(([\w\d])[\w\d]*)/).map{|h,i|f[j=i.upcase]?nil:(f[j]=!p; h)}.compact.join' ';end

#~ s = "Ferulas flourish in gorgeous gardens."
#~ p s.split

require 'minitest/autorun'
class FirstLetterTest < Minitest::Test
  def test_1
    assert_equal("Ferulas in gorgeous",m("Ferulas flourish in gorgeous gardens."))
    assert_equal("Ferulas in gorgeous",m_long("Ferulas flourish in gorgeous gardens."))
  end
  def test_2
    assert_equal("Take all first words each letter is",m("Take all first words for each letter... this is a test"))
    assert_equal("Take all first words each letter is",m_long("Take all first words for each letter... this is a test"))
  end
  def test_3
    assert_equal("Look _ There are 3 dogs",m("Look ^_^ .... There are 3 little dogs :)"))
    assert_equal("Look _ There are 3 dogs",m_long("Look ^_^ .... There are 3 little dogs :)"))
  end
  def test_4
    assert_equal("maybe some day 1 plus 2 could result in 3",m("...maybe some day 1 plus 2 plus 20 could result in 3"))
    assert_equal("maybe some day 1 plus 2 could result in 3",m_long("...maybe some day 1 plus 2 plus 20 could result in 3"))
  end
end

В Regex, \wвключает в себя цифры символов, поэтому [\w\d]может быть заменен на \w. Кроме того, если nilзначения находятся в массиве при вызове join' '(или, что еще лучше, *' 'это сокращение, которое вы можете использовать для сохранения большего количества байтов), они исчезают, поэтому вызов to compactне требуется .
Value Ink

@KevinLau Спасибо. Это \w\dсмущает меня. Но если я удалю, compactя получу дополнительные пробелы, (см. ['x',nil,'x']*'y' == 'xyyx'). Или я что-то пропустил?
Кнут

Ой, ты прав. В этом случае (list-[p])сохраняются байты list.compact. Кроме того, /\w/эквивалентно /[\w]/. Наконец, можно заменить nilс , pи ваш !pс 1(так как ваш хэш нужно только truthy значения в нем)
Значение Ink

Спасибо, я добавил ваши замечания, замена nilс pне работает. Если я использую его внутри своего кода, я получаю синтаксическую ошибку. Я должен инкапсулировать, как (p)- но тогда у меня снова 3 символа.
Кнут

Флип троичного , а затем он работает , чтобы сохранить байты: !f[j=i.upcase]?(f[j]=1;h):p. Также только подумал об этом, но из-за индексации строк, использование s.scan(/\w+/)и удаление iв пользу h[0]работ тоже.
Value Ink

1

grep и awk, 68 56 байт

Сценарий:

echo `grep -o '\w*'|awk '!x[tolower(substr($0,1,1))]++'`

Объяснение:

  • grep -o соответствует юридическим словам, печатая каждое на отдельной строке.

  • awkпринимает первую букву каждой строки substr, делает ее строчной, а затем увеличивает значение записи хеш-таблицы с этим ключом. Если значение было сброшено до приращения, строка печатается.

  • echo ... превращает строки обратно в слова

Ранее я пытался создать решение, не awkиспользуя uniq,sort , grepи , bashно упал чуть меньше. История в редакциях.

Спасибо Деннису за некоторые улучшения, которые я пропустил.


0

Python 3.5, 138 байт:

import re;lambda o,t=[]:''.join([y[0]for y in[(u+' ',t.append(u[0].lower()))for u in re.sub('\W+',' ',o).split()if u[0].lower()not in t]])

В основном то, что происходит, это ..

  1. Используя простое регулярное выражение, программа заменяет все символы, кроме строчных и прописных букв, цифр или подчеркиваний в данной строке пробелами, а затем разбивает строку на эти пробелы.
  2. Затем, используя понимание списка, создайте список, который перебирает все слова в разделенной строке, и добавляйте первые буквы каждого слова в список «t».
  3. В процессе, если первая буква текущего слова НЕ уже находится в списке «t», то это слово и завершающий пробел добавляются в текущий создаваемый список. В противном случае список продолжается добавлением первых букв каждого слова в список «t».
  4. Наконец, когда все слова в разбиении были повторены, слова в новом списке объединяются в строку и возвращаются.

0

PHP 120 байтов

function a($s){foreach(preg_split('/\W/',$s)as$w)if(!$o[ucfirst($w[0])]){$o[ucfirst($w[0])]=$w;}return implode(" ",$o);}

Это генерирует кучу предупреждений, но это нормально.


Это functionнеобходимо?
AL

0

Javascript ES6, 108 107 символов

107 символов, строка результата обрезается

r=s=>s.split``.reverse().join``
f=s=>r(r(s).replace(/\b\w*(\w)\b(?=.*\1\b)/gi,'')).replace(/\W+/g,' ').trim()

Тест:

["Take all first words for each letter... this is a test",
"Look ^_^ .... There are 3 little dogs :)",
"...maybe some day 1 plus 2 plus 20 could result in 3"
].map(f) + '' == [
"Take all first words each letter is",
"Look _ There are 3 dogs",
"maybe some day 1 plus 2 could result in 3"
]


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