Finestra pangrammatica più corta


15

Un pangram è una frase o un estratto che contiene tutte le ventisei lettere dell'alfabeto, come è dimostrato in questa sfida di golf del codice . Tuttavia, una finestra pangrammatica è un pangramma sotto forma di un segmento di testo, che può terminare o iniziare a metà di una parola, trovata da qualche parte all'interno di un'opera più ampia. Questi si verificano naturalmente ovunque, essendo sottoinsiemi propri di veri pangrammi, quindi verificare se qualcosa contenga una finestra pangrammatica sarebbe noioso e anche in precedenza era stato fatto.

Quindi, siamo interessati a trovare il più piccolo che ci sia in un determinato pezzo di testo in base alla sua lunghezza della lettera! Nel codice più breve possibile in byte, ovviamente, per adattarsi al tema.

Regole e linee guida

  • Ricevi una stringa come input e restituisce la stringa della finestra pangrammatica più piccola nell'input se ce n'è una. In caso contrario, restituisce un valore booleano falso o una stringa vuota.
  • Il fatto che una stringa sia una finestra pangrammatica o meno non fa distinzione tra maiuscole e minuscole e dipende solo dalle 26 lettere, non da punteggiatura o numeri o altri simboli dispari.
  • Allo stesso modo, la lunghezza delle lettere di una finestra pangrammatica è il numero totale di quante apparizioni di lettere si verificano in essa da sole, e non semplicemente il numero di ogni personaggio. Il valore restituito deve essere il più piccolo in base a questo conteggio. Dopotutto siamo linguisti, non programmatori.
  • L'output di una finestra pangrammatica deve tuttavia essere una sottostringa esatta dell'input, contenente la stessa maiuscola e punteggiatura, ecc.
  • Se sono presenti più finestre pangrammatiche più brevi della stessa lunghezza di lettera, restituire una di esse.

Casi test

'This isn't a pangram.'
==> False

'Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).'
==> 'Quick-Brown-Fox (the one who jumped over some lazy ig'

'"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.'
==> 'ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ'

1
Per l'ultimo caso di test, perché non viene The five boxing wizards jump quicklyrestituito?
Blue,

1
Per il secondo caso, è consentito lo spazio che precede il Q? Non si aggiunge al conteggio delle lettere.
Neil,

2
@muddyfish Perché ha 31 lettere, mentre l'output atteso ne ha solo 26.
Martin Ender

4
Bella prima domanda!
Rɪᴋᴇʀ

2
Sì. Nessun motivo non dovrebbe essere. Prendere il minimo "vero" nello spirito della domanda, ma non è necessario.
Reecer6,

Risposte:


6

Pyth, 20 16 14 byte

hol@GNf!-GrT0.:

Spiegazione:

             .: - substrings of input()
      f!-GrT0   - filter to ones which contain the alphabet
 ol@GN          - sort by number of alphabetical chars
h               - ^[0]

      f!-GrT0   - filter(lambda T:V, substrings)
          rT0   -    T.lower()
        -G      -   alphabet-^
       !        -  not ^

 o              - sort(^, lambda N:V)
   @GN          -   filter_presence(alphabet, N)
  l             -  len(^)

Provalo qui!

Quando non esiste una soluzione corretta, il programma esce con un errore senza output su stdout.


Sembra che tu non abbia aggiornato il codice nel primo blocco di codice. Inoltre !-GrT0è più breve per la condizione del filtro, credo. Penso anche che ti serva lper far funzionare correttamente l'ordinamento.
FryAmTheEggman,

Oh, ho sbagliato, intendevo il collegamento. Nel tuo link hai ancora il l, e senza di esso ottieni risultati diversi . Credo che il problema siano le lettere ripetute, ma non sono sicuro al 100%.
FryAmTheEggman,

Quindi importa - e grazie per l'ottimizzazione!
Blue,


2

Rubino, 100 byte

Restituisce zero se non viene trovata alcuna finestra.

->s{r=0..s.size
(r.map{|i|s[i,r.find{|j|(?a..?z).all?{|c|s[i,j]=~/#{c}/i}}||0]}-['']).min_by &:size}

2

JavaScript (ES6), 139 138 136 byte

s=>[r=l="",...s].map((_,b,a)=>a.map((c,i)=>i>b&&(t+=c,z=parseInt(c,36))>9&&(v++,n+=!m[z],m[z]=n<26||l&&v>l||(r=t,l=v)),t=m=[],v=n=0))&&r

Salvato 2 byte grazie a @Neil!

frastagliato

var solution =

s=>
  [r=l="",...s].map((_,b,a)=> // b = index of start of window to check
    a.map((c,i)=>
      i>b&&(
        t+=c,
        z=parseInt(c,36)
      )>9&&(
        v++,
        n+=!m[z],
        m[z]=
          n<26||
          v>l&&l||(
            r=t,
            l=v
          )
      ),
      t=m=[],
      v=n=0
    )
  )
  &&r
<textarea cols="70" rows="6" id="input">Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).</textarea><br /><button onclick="result.textContent=solution(input.value)">Go</button><pre id="result"></pre>


Non puoi usare [r=l="",...s].map((_,b,a)=>?
Neil,

@Neil Grazie, mi dimentico sempre del terzo parametro nella mapfunzione.
user81655,

Penso che @ edc65 possa battere questo, però, ho unito il codice per le sue sottostringhe esplose con quello per il suo tester di pangram e ho finito con una funzione di 134 byte.
Neil,

Il mio meglio è 142 finora
edc65,

Purtroppo non pensavo di salvarlo e il mio PC si è bloccato, quindi ora non so cosa avevo; il meglio che posso fare ora è 138 byte.
Neil,

2

PowerShell v2 +, 218 byte

param($a)$z=@{};(0..($b=$a.length-1)|%{($i=$_)..$b|%{-join$a[$i..$_]}})|%{$y=$_;$j=1;65..90|%{$j*=$y.ToUpper().IndexOf([char]$_)+1};if($j){$z[($y-replace'[^A-Za-z]').Length]=$y}}
($z.GetEnumerator()|sort Name)[0].Value

Sì, quindi la manipolazione della sottostringa (non ci sono built-in) non è davvero il punto forte di PowerShell ...

Prendiamo input param($a)e impostiamo una nuova hashtable vuota$z . Questo sarà il nostro deposito di sottostringhe pangrammatiche candidate.

Usando una leggera modifica del mio codice dai substrati esplosi , costruiamo tutte le sottostringhe dell'input. Sì, anche sottostringhe di un solo carattere di punteggiatura. Questo è , non . ;-)

Tutte queste sottostringhe sono incapsulate in parentesi e convogliate in un altro anello con |%{...}. Impostiamo temporaneamente $yla sottostringa corrente, impostiamo un contatore helper $je iniziamo un altro ciclo 65..90|%{...}, comodamente sopra i codici char ASCII per le lettere maiuscole. Ogni ciclo interno, prendiamo $y, rendiamo tutto maiuscolo e tiriamo fuori .IndexOfquel particolare carattere. Dal momento che questo restituirà -1se non trovato, noi +1il risultato prima di moltiplicarlo in $j. Questo assicura che se non viene trovato alcun personaggio,$j sarà uguale a zero.

Il che è esattamente ciò di cui ifsi tratta. Se $jè diverso da zero, significa che ogni lettera è stata trovata almeno una volta nella sottostringa $y, quindi è necessario aggiungerla al nostro pool di candidati. Lo facciamo prendendo $ye -replaceingingendo ogni non-lettera senza nulla, il che ci fornisce la lunghezza della lettera di quella sottostringa. Lo usiamo come indice in hashtable $ze store$y in quell'indice. Questo ha la stranezza di sovrascrivere sottostringhe della stessa lunghezza di lettera con quella che si verifica "più lontana" nella stringa originale, ma ciò è consentito dalle regole, poiché siamo preoccupati solo per la lunghezza della lettera.

Infine, dobbiamo $zsistemare ed estrarre il più piccolo. Dobbiamo usare la .GetEnumeratorchiamata per ordinare gli oggetti all'interno $z , quindi sortquelli su Name(cioè l'indice di lunghezza dall'alto), selezionando [0]quello (cioè il più corto) e emettendo il suo .Value(cioè la sottostringa). Se tale sottostringa non si adatta, ciò genererà un errore ( Cannot index into a null array) quando tenta di indicizzare $ze non genera nulla, il che è falso in PowerShell. (il terzo caso di test di seguito ha un cast esplicito come[bool] per mostrarlo)

Casi test

PS C:\Tools\Scripts> .\golfing\shortest-pangrammatic-window.ps1 '"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.'
ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" 

PS C:\Tools\Scripts> .\golfing\shortest-pangrammatic-window.ps1 'Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).'
Quick-Brown-Fox (the one who jumped over some lazy ig

PS C:\Tools\Scripts> [bool](.\golfing\shortest-pangrammatic-window.ps1 "This isn't a pangram.")
Cannot index into a null array.
At C:\Tools\Scripts\golfing\shortest-pangrammatic-window.ps1:2 char:1
+ ($z.GetEnumerator()|sort Name)[0].Value
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : NullArray

False

2

Haskell, 180 byte

È stato difficile, ma davvero divertente senza importazioni.

l=['a'..'z']
u=['A'..'Z']
f&[]=[];f&x=x:f&f x
g#h=(.g).h.g
f x|v<-[y|y<-(tail&)=<<(init&x),and$zipWith((`elem`y)#(||))l u]=last$[]:[z|z<-v,all((length.filter(`elem`l++u))#(<=)$z)v]

Molto meno golfato:

lowerCase = ['a'..'z']
upperCase = ['A'..'Z']

f & x = takeWhile (not . null) $ iterate f x

(#) = flip on

subStrings x = (tail &) =<< (init & x)

pangram p = and $ zipWith ((`elem` p) # (||)) lowerCase upperCase

leqLetters x y = (length . filter (`elem` lowerCase ++ upperCase)) # (<=)

fewestLetters xs = [ x | x <- xs, all (leqLetters x) xs]

safeHead [] = ""
safeHead xs = head xs

f x = safeHead . fewestLetters . filter pangram . subStrings

Sorpresa, sorpresa: è davvero lento.


2

Oracle SQL 11.2, 461 byte

WITH s AS (SELECT SUBSTR(:1,LEVEL,1)c,LEVEL p FROM DUAL CONNECT BY LEVEL<=LENGTH(:1)),v(s,f,l)AS(SELECT c,p,p FROM s UNION ALL SELECT s||c,f,p FROM v,s WHERE p=l+1),c AS(SELECT CHR(96+LEVEL)c FROM DUAL CONNECT BY LEVEL<27),a AS(SELECT LISTAGG(c)WITHIN GROUP(ORDER BY 1) a FROM c)SELECT MIN(s)KEEP(DENSE_RANK FIRST ORDER BY LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')),0))FROM(SELECT s,f,SUM(SIGN(INSTR(LOWER(s),c)))x FROM v,c GROUP BY s,f),a WHERE x=26;

Un-golfed

WITH s AS (SELECT SUBSTR(:1,LEVEL,1)c,LEVEL p FROM DUAL CONNECT BY LEVEL<=LENGTH(:1))
,v(s,f,l) AS
(
  SELECT c,p,p FROM s
  UNION ALL
  SELECT s||c,f,p FROM v,s WHERE p=l+1 
)
,c AS(SELECT CHR(96+LEVEL)c FROM DUAL CONNECT BY LEVEL<27)
,a AS(SELECT LISTAGG(c)WITHIN GROUP(ORDER BY 1) a FROM c)
SELECT MIN(s)KEEP(DENSE_RANK FIRST ORDER BY LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')),0))
FROM(SELECT s,f,SUM(SIGN(INSTR(LOWER(s),c)))x FROM v,c GROUP BY s,f),a
WHERE x=26

La svista divide l'input in caratteri e restituisce anche la posizione di ciascun carattere.

La vista ricorsiva vrestituisce ogni sottostringa dell'input
s è la sottostringa
f la posizione del primo carattere della sottostringa
l la posizione dell'ultimo carattere aggiunto alla sottostringa corrente

La cvista restituisce l'alfabeto, una lettera alla volta

La avista restituisce l'alfabeto concatenato come una singola stringa

SELECT s,f,SUM(SIGN(INSTR(LOWER(s),c))
Restituisce per ogni sottostringa il numero di lettere distinte presenti in essa
INSTRrestituisce la pos di una lettera nella sottostringa, 0 se non presente
SIGNrestituisce 1 se pos> 0, 0 se pos = 0

WHERE x=26
Filtra la sottostringa contenente l'intero alfabeto

TRANSLATE(LOWER(s),' '||a,' ')
Elimina ogni lettera dalla sottostringa

LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')
La lunghezza in lettere è la lunghezza della sottostringa meno la lunghezza della sottostringa senza lettere

SELECT MIN(s)KEEP(DENSE_RANK FIRST ORDER BY LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')),0))
Mantiene solo la sottostringa con il conteggio delle lettere più piccolo.
Se ce n'è più di uno, viene mantenuto il primo, ordinato come stringhe in ordine crescente


2

Python 3, 171, 167, 163, 157 , 149 byte.

Salvato 4 byte grazie a DSM.
Risparmiato 8 byte grazie a RootTwo.

lambda x,r=range:min([x[i:j]for i in r(len(x))for j in r(len(x))if{*map(chr,r(65,91))}<={*x[i:j].upper()}]or' ',key=lambda y:sum(map(str.isalpha,y)))

Dover ordinare in base al numero di lettere mi sta uccidendo.

Casi test:

assert f("This isn't a pangram.") == ' '
assert f("Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).") == ' Quick-Brown-Fox (the one who jumped over some lazy ig', f("Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).")
assert f('"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.') == '. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ', f('"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.')

Non pensare che .upper()sia necessario nella funzione chiave.
Radice Due

@RootTwo Oops, sì, hai ragione. Grazie.
Morgan Thrapp,

1

PowerShell (v4), 198156 byte

param($s)
-join(@(1..($y=$s.Length)|%{$w=$_
0..$y|%{(,@($s[$_..($_+$w)]))}}|?{($_-match'[a-z]'|sort -U).Count-eq26}|sort -Pr {($_-match'[a-z]').count})[0])


# Previous 198 byte golf
$a,$b,$c=@(1..($s="$args").Length|%{$w=$_
0..($s.Length-$w)|%{if((($t=$s[$_..($_+$w)]-match'[a-z]')|sort -u).Count-eq26){(,@($t.Length,$_,$w))}}}|sort -pr{$_[0]})[0]
(-join($s[$b..($b+$c)]),'')[!$a]

Casi test

PS C:\> .\PangramWindow.ps1 "This isn't a pangram."


PS C:\> .\PangramWindow.ps1 'Everyone knows about that infamous Quick-Brown-Fox (the one who jumped over some lazy ignoramus of a dog so many years ago).'
Quick-Brown-Fox (the one who jumped over some lazy ig

PS C:\> .\PangramWindow.ps1 '"The five boxing wizards jump quickly." stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. "ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!" he shouted to the heavens.'
ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!

Spiegazione incolume dell'originale

È un anello annidato a forza bruta che rende finestre scorrevoli di tutte le dimensioni:

.SubString(0, 1) -> slide window over the string
.SubString(0, 2) -> slide window over the string
..
.SubString(0, string.Length) -> slide window over the string

Per ogni finestra, filtra solo le lettere (corrispondenza regex insensibile al maiuscolo per impostazione predefinita), esegue i caratteri rimanenti attraverso un filtro univoco, controlla se ci sono 26 caratteri univoci come test del pangram.

Tutte le finestre con pangrammi vengono trasformate in triplette di (numero di lettere inclusi i duplicati, indice iniziale, lunghezza della finestra inclusa la punteggiatura) , che vengono ordinate per trovare il numero più breve in base al conteggio complessivo dei caratteri, il primo viene scelto e la stringa di output costruita da quella .

C'è un sacco di indicizzazione al di fuori dei limiti della stringa, per cui PowerShell restituisce utilmente $ null, invece di generare eccezioni.

NB. il nuovo 156 byte è lo stesso approccio, ma riscritto per utilizzare la pipeline molto di più.

$string = "$args"

# increasing window widths, outer loop
$allPangramWindows =  foreach ($windowWidth in 1..$string.Length) {

    # sliding windows over string, inner loop
    0..($string.Length - $windowWidth) | ForEach {

        # slice window out of string, returns a char array
        $tmp = $string[$_..($_+$windowWidth)]

        # filter the char array to drop not-letters
        $tmp = $tmp -match '[a-z]'

        # Drop duplicate letters
        $tmpNoDupes = $tmp | sort -Unique

        # If we're left with a 26 character array, this is a pangrammatic window. Output
        # a PowerShell-style tuple of count of letters, start index, width.
        if($tmpNoDupes.Count -eq 26){
            (,@($tmp.Length,$_,$windowWidth))
        }
    }
}

# Force the result into an array (to handle no-results), sort it
# by the first element (num of letters in the window, total)
$allPangramWindows = @( $allPangramWindows | sort -Property {$_[0]} )

# take element 0, a window with the fewest letters
$windowCharCount, $windowStart, $WindowEnd = $allPangramWindows[0]

# uses the results to find the original string with punctuation and whitespace
if ($windowLen) {
    $string[$windowStart..($windowStart + $windowLen)] -join ''
}

NB. non sono sicuro che la versione ungolfed funzioni, perché non l'ho scritto poi golf, è solo per l'esposizione.


0

Haskell, 123 byte

import Data.Lists
import Data.Char
h x=take 1$sortOn((1<$).filter isAlpha)[e|e<-powerslice x,['a'..'z']\\map toLower e==""]

Definisce una funzione h, che restituisce l'elenco vuoto se non c'è una finestra pangrammatica o un elenco di un elemento con la finestra minima. Esempio di utilizzo:

*Main>  h "'The five boxing wizards jump quickly.' stated Johnny, before beginning to recite the alphabet with a bunch of semicolons in the middle. 'ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ!' he shouted to the heavens."
[". 'ABCDEFGHI;;;;;;;;;;;;;;;JKLMNOPQRSTUVWXYZ"]

Come funziona:

          [e|e<-powerslice x                  ]  -- for all continuous subsequences
                                                 -- e of the input  
                ,['a'..'z']\\map toLower e==""   -- keep those where the list
                                                 -- difference with all letters is
                                                 -- empty, i.e. every letter appears
                                                 -- at least once
    sortOn((1<$).filter isAlpha)                 -- sort all remaining lists on
                                                 -- their length after removing all
                                                 -- non-letters -> (1<$) see below
take 1                                           -- take the first, i.e. the minimum


calculating the length of a list: we're not interested in the length itself, but
in the relative order of the length. (1<$) replaces each element in a list with
the number 1, e.g. "abc" -> "111", "abcd" -> "1111", etc. Such '1'-strings have
the same order as the length of the original list. One byte saved!
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.