Trova la prima parola che inizia con ogni lettera


25

Data una stringa, trova la prima parola che inizia con ogni lettera (senza distinzione tra maiuscole e minuscole).

Campione

Utilizzando Ferulas flourish in gorgeous gardens.come input:

"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`

Quindi, l'output per questo esempio dovrebbe essere le parole corrispondenti unite da un unico spazio:

"Ferulas in gorgeous"

Sfida

Sia l'input che l'output devono essere una rappresentazione di stringhe o l'alternativa più vicina nella tua lingua.

Programma o funzione consentiti.

Si può considerare una parola di essere almeno uno di: lowercase or uppercase letters, digits, underscore.

Questo è , la risposta più breve in byte vince.

Altri campioni:

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"

Sono consentiti gli spazi iniziali / finali? <s> Posso presumere che le parole siano separate da uno spazio nella stringa originale? </s>
Qwertiy

L'ho capito dagli esempi, quindi c'è <s> </s> nel commento. Che dire di tagliare gli spazi?
Qwertiy,

Risposte:


17

Retina , 28 byte:

M! I` \ b (\ w) (? <! \ B \ 1. +) \ W *
¶
 
  • M! - Abbina ogni opera e stampa tutte le parole separate da nuove righe.
  • i - Ignora il caso.
  • \b(\w) - Cattura la prima lettera di ogni parola
  • (?<!\b\1.+)- Dopo aver abbinato la lettera, controlla se non c'era una parola precedente che inizia con la stessa lettera. \1.+assicura almeno due caratteri, quindi stiamo saltando la parola corrente.
  • \w*- corrisponde al resto della parola.
    Quanto sopra corrisponde solo alle parole: tutti gli altri caratteri vengono rimossi.
  • ¶\n - Sostituisci newline con spazi.

Provalo online!


9

Retina , 45 byte

I` \ b ((\ w) \ w *) \ b (? <= \ b \ 2 \ w * \ b. +)

\ W +
 
^ | $

Utilizza semplicemente una singola regex per rimuovere le parole successive che iniziano con lo stesso \wcarattere (senza distinzione tra maiuscole e minuscole con l' iopzione), converte le esecuzioni \Win un singolo spazio, quindi rimuove qualsiasi spazio iniziale / finale dal risultato.

Provalo online!

Modifica: vedi la risposta di @ Kobi per una versione più breve usandoM!`


Accidenti, a malapena mi ha battuto! Non sono riuscito a capire il lookbehind però.
GamrCorps il

3
Ho aggiunto un'altra risposta alla Retina: penso che sia OK se sono abbastanza diversi (il concetto di base è simile, ovviamente).
Kobi,

1
@Kobi È molto meglio, quindi sono felice di vederlo :) Mi fa capire quanto più ho bisogno di imparare sulle opzioni di linea di Retina e cosa no.
Sp3000,

Potresti farlo per risparmiare qualche byte? i` \b((\w)\w*)\b(?<=\b\2\w*\b.+)(uno spazio prima del primo \b) Le linee successive non sono necessarie?
Leaky Nun

@KennyLau Sfortunatamente, non penso che funzioni perché le parole non sono necessariamente separate da spazi, ad es.a...a -> a
Sp3000

9

JavaScript (ES6), 73 71 byte

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

Salvato 2 byte grazie a @ edc65!

Test

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


Usando parseInt("_",36) = NaN? Bestemmia!
Sp3000,

1
Il fatto divertente è: funziona @ Sp3000
edc65

L'uso di u = regexp è davvero intelligente. Salva 2 bytes=>s.match(u=/\w+/g).filter(w=>u[w=parseInt(w[0],36)]?0:u[w]=1).join' '
edc65

@ edc65 Grazie. In realtà è abbastanza conveniente che ci siano 37 possibili uscite per una singola base-36 cifre.
user81655

7

Pyth, 23 byte

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

Provalo online: Dimostrazione o Test Suite

J:z"\w+"1trova tutte le parole nell'input usando regex \w+e le memorizza in J.

.grhk0Jraggruppa le parole in base alla loro prima lettera minuscola, hMprende la prima da ciascun gruppo, xDJordina queste parole in base al loro indice nella stringa di input e jdinserisce degli spazi tra loro.


4

Perl 6, 39 byte

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

1
42 byte che risolve le parole che devono corrispondere \w+e gioca a golf la substrparte
Jo King

3

C, 142 132 122 byte

10 byte più leggeri grazie a @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();}

Stampa uno spazio finale dopo l'ultima parola di output.


1
puoi radere i controlli per c>47e c<58usando isalnuminvece diisalpha
tucuxi il

3

MATL , 23 byte

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

Questo prende in prestito l'idea di Jakube di usare una regexp per rimuovere personaggi indesiderati e dividere allo stesso tempo.

L'input è una stringa racchiusa tra virgolette singole.

Provalo online!

Spiegazione

'\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

Tasti 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

Spiegazione:

: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

Sono davvero deluso da quanto tempo è questo. I caratteri "non valido" (tutto tranne a-z, A-Z, _e lo spazio) veramente buttato fuori di me. Sono sicuro che c'è un modo migliore per farlo:

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

Dal momento che le \hpartite si aspettano tutto ciò per lo spazio, ma non riesco a capire come mettere il metachar in un intervallo. Se qualcuno ha dei suggerimenti, mi piacerebbe ascoltarli.


3
perché a-zA-Z_e no \w? le cifre sono valide
edc65

2

Julia, 165 155 151 129 102 byte

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)])," ")

Questa è una funzione che accetta una stringa e restituisce una stringa.

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

Hai salvato 53 byte con l'aiuto di Sp3000!



2

C # (LINQPAD) - 136 128 byte

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 byte

Codice:

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

Provalo online!

Spiegazione:

Generiamo innanzitutto tutti i caratteri che devono essere eliminati dalla stringa di input utilizzando 94L32+ç( Prova qui ). Uniamo questa stringa usando Je rimuovendo ciò [a-zA-Z0-9_]che è memorizzato in žj ( prova qui ). Rimuoviamo tutti i caratteri che si trovano nella seconda stringa dalla prima stringa, che ci lascerà:

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

Questo può anche essere testato qui . NoiD uplicing e memorizziamo Xcon il Ucomando-. Quindi rimuoviamo tutti i caratteri presenti in questa stringa dall'input. Dividiamo quindi gli spazi bianchi usando ð¡e rimuovendo tutte le stringhe vuote (usando ""K). Ora abbiamo questo .

Questa è la versione pulita dell'input, con cui lavoreremo. Mappiamo su ogni elemento usando v. Questo utilizza ycome variabile stringa. Prendiamo il primo carattere della stringa usando ¬e premi X, che contiene una stringa con tutti i caratteri proibiti ( !"#$%&'()*+,-./:;<=>?@[\]^`{|}~). Controlliamo se ill versione maiuscola del primo carattere, (che verrà anche ©opzionata sul registro), è in questa stringa usando å. Coperto da questa parte: ï>ise la prima lettera non esiste nella stringa di caratteri proibiti ( X), aggiungiamo questa lettera all'elenco dei caratteri proibiti (terminato con X®«U) e spingiamo yin cima alla pila.

Alla fine, quando le stringhe vengono filtrate, uniamo la pila per spazi con ðý .


1
... spiegazione? :-)
Luis Mendo

@LuisMendo Grazie per avermelo ricordato! Fatto :)
Adnan,

2

PHP

Ispirato dall'uso di regex nella maggior parte delle risposte, inizialmente ho provato a farlo senza usare regex solo per mostrare una variazione ordinata, ma il punto critico di non avere stringhe pulite come input ha rovinato quell'idea. Triste.

Con wrapper funzione, 89 byte

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

Senza wrapper di funzioni (che richiedono $ s pre-dichiarato), 73 byte

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

Spiegazione:

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.

Il mio unico rimpianto è che non sono riuscito a trovare un modo più veloce di controllare / convertire il maiuscolo / minuscolo.


2

Python, 103 byte

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

Lua, 172 byte

È finito molto più a lungo che volevo ...

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

Scherzi a parte, 43 byte

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

Provalo online!

La mancanza di capacità regex ha reso questo molto più difficile di quanto non fosse necessario.

Spiegazione:

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 byte

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

O con la definizione del metodo 88 byte

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

Non golfato e con unit test:

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

In Regex, \winclude i caratteri numerici, quindi [\w\d]può essere sostituito con \w. Inoltre, se i nilvalori sono in un array quando si chiama join' '(o meglio, *' 'è una scorciatoia che è possibile utilizzare per salvare più byte), svaniscono, quindi la chiamata a compactnon è necessaria.
Value Ink

@KevinLau Grazie. Il \w\dè imbarazzante per me. Ma se rimuovo compactottengo spazi aggiuntivi, (vedi ['x',nil,'x']*'y' == 'xyyx'). O mi sono perso qualcosa?
Knut

Spiacenti, hai ragione. In tal caso, (list-[p])salva i byte sopra list.compact. Inoltre, /\w/equivale a /[\w]/. Infine, è possibile sostituire il nilcon pe il vostro !pcon 1(poiché il vostro hash ha solo bisogno di valori truthy in esso)
Valore inchiostro

Grazie, ho aggiunto le tue osservazioni, la sostituzione di nilcon pnon funziona. Se lo uso nel mio codice, viene visualizzato un errore di sintassi. Devo incapsulare come (p)- ma poi ho di nuovo 3 caratteri.
Knut

Capovolgere il ternario e quindi funziona per salvare un byte: !f[j=i.upcase]?(f[j]=1;h):p. Anche solo pensato a questo, ma a causa dell'indicizzazione delle stringhe, utilizzare s.scan(/\w+/)e rimuovere anche le funzioni ia favore h[0].
Value Ink

1

grep e awk, 68 56 byte

Il copione:

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

Spiegazione:

  • grep -o corrisponde alle parole legali, stampandole ciascuna sulla propria riga.

  • awkprende la prima lettera di ogni riga con substr, la rende minuscola e quindi incrementa una voce con hash con quel tasto. Se il valore non era impostato prima dell'incremento, la linea viene stampata.

  • echo ... trasforma le linee in parole

Ho già cercato di creare una soluzione senza awk, utilizzando uniq, sort, grepe bashtuttavia mancato di poco. Storia nelle modifiche.

Grazie a Dennis per alcuni miglioramenti, mi sono perso.


0

Python 3.5, 138 byte:

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]])

Fondamentalmente, quello che sta succedendo è ...

  1. Utilizzando una semplice espressione regolare, il programma sostituisce tutti i caratteri, tranne lettere minuscole o maiuscole, cifre o caratteri di sottolineatura nella stringa data con spazi, quindi suddivide la stringa in tali spazi.
  2. Quindi, usando la comprensione dell'elenco, crea un elenco che scorre tutte le parole nella stringa divisa e aggiungi le prime lettere di ogni parola all'elenco "t".
  3. Nel processo, se la prima lettera della parola corrente NON è già nell'elenco "t", quella parola e uno spazio finale vengono aggiunti all'elenco corrente in fase di creazione. Altrimenti, l'elenco continua aggiungendo le prime lettere di ogni parola all'elenco "t".
  4. Infine, quando tutte le parole nella divisione sono state ripetute, le parole nel nuovo elenco vengono unite in una stringa e restituite.

0

PHP 120bytes

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

Questo genera un sacco di avvertimenti ma va bene.


È functionnecessario?
AL

0

Javascript ES6, 108 107 caratteri

107 caratteri, la stringa del risultato viene tagliata

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

Test:

["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"
]


0

Tcl , 150 byte

proc F {s D\ {}} {lmap w [split $s] {regsub -all \[^\\w] $w "" f
if {![dict e $D [set k [string tol [string in $f 0]]]]} {dict se D $k $f}}
dict v $D}

Provalo online!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.