Fenêtre pangrammatique la plus courte

15

Un pangram est une phrase ou un extrait qui contient les vingt-six lettres de l'alphabet, comme le démontre ce défi de golf de code . Cependant, une fenêtre pangrammatique est un pangram sous la forme d'un segment de texte, qui peut se terminer ou commencer à mi-chemin d'un mot, trouvé quelque part dans une œuvre plus grande. Celles-ci se produisent naturellement partout, étant des sous-ensembles appropriés de vrais pangrammes, donc vérifier simplement si quelque chose contient une fenêtre pangrammatique serait ennuyeux et cela a déjà été fait auparavant.

Donc, nous sommes intéressés à trouver le plus petit dans un morceau de texte donné en fonction de sa longueur de lettre! Dans le code le plus court possible en octets, bien sûr, pour s'adapter au thème.

Règles et directives

  • Recevez une chaîne en entrée et renvoyez la chaîne de la plus petite fenêtre pangrammatique dans l'entrée s'il y en a une. Si ce n'est pas le cas, renvoyez un booléen faux ou une chaîne vide.
  • Qu'une chaîne soit ou non une fenêtre pangrammatique est insensible à la casse et ne dépend que des 26 lettres, pas de la ponctuation ou des nombres ou d'autres symboles impairs.
  • De même, la longueur des lettres d' une fenêtre pangrammatique est le nombre total d'apparitions de lettres qui s'y trouvent seules, et pas simplement le nombre de chaque caractère. La valeur retournée doit être la plus petite en fonction de ce nombre. Nous sommes des linguistes, après tout, pas des programmeurs.
  • Une sortie d'une fenêtre pangrammatique doit cependant être une sous-chaîne exacte de l'entrée, contenant les mêmes majuscules et ponctuation, etc.
  • S'il existe plusieurs fenêtres pangrammatiques les plus courtes de la même longueur de lettre, renvoyez l'une d'entre elles.

Cas de 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'
Reecer6
la source
1
Pour le dernier cas de test, pourquoi n'est-il pas The five boxing wizards jump quicklyretourné?
Bleu
1
Pour le deuxième cas, avez-vous droit à l'espace précédant le Q? Cela n'ajoute rien au nombre de lettres.
Neil
2
@muddyfish Parce qu'il a 31 lettres, alors que la sortie attendue n'en a que 26.
Martin Ender
4
Belle première question!
Rɪᴋᴇʀ
2
Oui. Aucune raison que ça ne devrait pas l'être. Prendre le "vrai" minimum dans l' esprit de la question, mais ce n'est pas nécessaire.
Reecer6

Réponses:

6

Pyth, 20 16 14 octets

hol@GNf!-GrT0.:

Explication:

             .: - 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(^)

Essayez-le ici!

Lorsqu'il n'y a pas de solution correcte, le programme se termine avec une erreur sans sortie vers stdout.

Bleu
la source
Vous semblez ne pas avoir mis à jour le code dans le premier bloc de code. Est également !-GrT0plus court pour l'état du filtre, je crois. Je pense aussi que vous avez besoin du lpour que le tri fonctionne correctement.
FryAmTheEggman
Oh, j'ai mal parlé, je voulais dire le lien. Dans votre lien, vous avez toujours le l, et sans lui, vous obtenez des résultats différents . Je crois que le problème vient des lettres répétées, mais je ne suis pas sûr à 100%.
FryAmTheEggman
C'est donc important - et merci pour l'optimisation!
Bleu
3

Pyth - 22 octets

\ o / FGITW!

h+ol@GrNZf}GS{rTZ.:z)k

Suite de tests .

Maltysen
la source
2

Ruby, 100 octets

Renvoie nil si aucune fenêtre n'est trouvée.

->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}
Encre de valeur
la source
2

JavaScript (ES6), 139 138 136 octets

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

Sauvegardé 2 octets grâce à @Neil!

Dentelé

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>

user81655
la source
Tu ne peux pas utiliser [r=l="",...s].map((_,b,a)=>?
Neil
@Neil Merci, j'oublie toujours le troisième paramètre de la mapfonction.
user81655
Je pense que @ edc65 peut battre cela cependant, j'ai fusionné le code de ses sous-chaînes éclatées avec celui de son testeur de pangrammes et je me suis retrouvé avec une fonction de 134 octets.
Neil
Jusqu'à présent, mon meilleur est 142
edc65
Malheureusement, je n'ai pas pensé à l'enregistrer et mon PC est tombé en panne alors maintenant je ne sais pas ce que j'avais; le mieux que je puisse faire maintenant est de 138 octets.
Neil
2

PowerShell v2 +, 218 octets

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

Oui, donc la manipulation de la sous-chaîne (il n'y a pas de fonction intégrée) n'est pas vraiment le point fort de PowerShell ...

Nous prenons des informations param($a)et définissons une nouvelle table de hachage vide$z . Ce sera notre stockage de sous-chaînes pangrammatiques candidates.

En utilisant une légère modification de mon code des sous- chaînes explosées , nous construisons toutes les sous-chaînes de l'entrée. Oui, même les sous-chaînes de ponctuation à un seul caractère. C'est du , pas . ;-)

Toutes ces sous-chaînes sont encapsulées dans des parens et canalisées dans une autre boucle avec |%{...}. Nous définissons temporairement $ynotre sous-chaîne actuelle, définissons un compteur d'assistance $jet commençons une autre boucle 65..90|%{...}, commodément sur les codes de caractères ASCII pour les lettres majuscules. Chaque boucle intérieure, nous la prenons, la rendons $ytout en majuscules et retirons .IndexOfce caractère particulier. Puisque cela reviendra -1s'il n'est pas trouvé, nous obtenons +1le résultat avant de le multiplier $j. Cela garantit que si aucun caractère n'est trouvé, $jsera égal à zéro.

C'est exactement de cela qu'il ifs'agit. Si $jest différent de zéro, cela signifie que chaque lettre a été trouvée au moins une fois dans la sous-chaîne $y, nous devons donc l'ajouter à notre pool de candidats. Nous le faisons en prenant $yet en -replaceingérant chaque non-lettre avec rien, ce qui nous donne la longueur de lettre de cette sous-chaîne. Nous l'utilisons comme index dans une table de hachage $zet stockons$y à cet index. Cela a la particularité d'écraser des sous-chaînes de la même longueur de lettre avec celle qui se trouve "la plus éloignée" dans la chaîne d'origine, mais cela est autorisé par les règles, car nous ne nous préoccupons que de la longueur de la lettre.

Enfin, nous devons trier $zet retirer le plus petit. Nous devons utiliser l' .GetEnumeratorappel afin de trier les objets à l'intérieur $z , puis sortceux sur Name(c'est-à-dire l'indice de longueur par le haut), en sélectionnant le [0]e (c'est-à-dire le plus court) et en sortant son .Value(c'est-à-dire la sous-chaîne). Si aucune telle sous-chaîne ne convient, cela lancera une erreur ( Cannot index into a null array) lorsqu'elle essaiera de $zs'indexer et de ne rien produire, ce qui est falsey dans PowerShell. (le troisième cas de test ci-dessous a une distribution explicite [bool]pour le montrer)

Cas de 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
AdmBorkBork
la source
2

Haskell, 180 octets

C'était dur, mais vraiment amusant sans importations.

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]

Beaucoup moins golfé:

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

Surprise, surprise: c'est vraiment lent.

Michael Klein
la source
2

Oracle SQL 11.2, 461 octets

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;

Non golfé

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 svue divise l'entrée en caractères et renvoie également la position de chaque caractère.

La vue récursive vrenvoie chaque sous-chaîne de l'entrée
s est la sous-chaîne
f la position du premier caractère de la sous-chaîne
l la position du dernier caractère ajouté à la sous-chaîne courante

La cvue renvoie l'alphabet, une lettre à la fois

La avue renvoie l'alphabet concaténé en une seule chaîne

SELECT s,f,SUM(SIGN(INSTR(LOWER(s),c))
Renvoie pour chaque sous-chaîne le nombre de lettres distinctes présentes dans celle-ci
INSTRrenvoie la pos d'une lettre dans la sous-chaîne, 0 si non présent
SIGNrenvoie 1 si pos> 0, 0 si pos = 0

WHERE x=26
Filtre la sous-chaîne contenant tout l'alphabet

TRANSLATE(LOWER(s),' '||a,' ')
Supprime chaque lettre de la sous-chaîne

LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')
La longueur en lettres est la longueur de la sous-chaîne moins la longueur de la sous-chaîne sans lettres

SELECT MIN(s)KEEP(DENSE_RANK FIRST ORDER BY LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')),0))
Conserve uniquement la sous-chaîne avec le plus petit nombre de lettres.
S'il y en a plus d'un, le premier, trié par ordre croissant, est conservé

Jeto
la source
2

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

4 octets enregistrés grâce à DSM.
8 octets enregistrés grâce à 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)))

Devoir trier en fonction du nombre de lettres me tue.

Cas de 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.')
Morgan Thrapp
la source
Ne pensez pas que .upper()c'est nécessaire dans la fonction clé.
RootTwo
@RootTwo Oups, oui, vous avez raison. Merci.
Morgan Thrapp
1

PowerShell (v4), 198 156 octets

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]

Cas de 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!

Explication non golfée de l'original

C'est une boucle imbriquée par force brute qui crée des fenêtres coulissantes de toutes tailles:

.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

Pour chaque fenêtre, il filtre uniquement les lettres (correspondance regex insensible à la casse par défaut), exécute les caractères restants via un filtre unique, vérifie s'il y a 26 caractères uniques comme test pangram.

Toutes les fenêtres avec des pangrammes sont transformées en triplets de (nombre de lettres, y compris les dupes, index de début, longueur de la fenêtre, y compris la ponctuation) , qui sont triés pour trouver le plus court par nombre total de caractères, le premier est choisi et la chaîne de sortie construite à partir de cela .

Il y a beaucoup d'indexation en dehors des limites de la chaîne, pour laquelle PowerShell renvoie utilement $ null, au lieu de lever des exceptions.

NB. le nouveau 156 octets est la même approche, mais réécrit pour utiliser le pipeline beaucoup plus.

$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. Je ne suis pas sûr que la version non golfée fonctionne, parce que je n'ai pas écrit ça puis je l'ai joué au golf, c'est juste pour une exposition.

TessellatingHeckler
la source
0

Haskell, 123 octets

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

Définit une fonction h, qui renvoie la liste vide s'il n'y a pas de fenêtre pangrammatique ou une liste d'un élément avec la fenêtre minimale. Exemple d'utilisation:

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

Comment ça fonctionne:

          [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!
nimi
la source