Ventana pangramática más corta

15

Un pangrama es una oración o extracto que contiene las veintiséis letras del alfabeto, como se demuestra en este código de desafío de golf . Sin embargo, una ventana pangramática es un pangrama en forma de algún segmento de texto, que puede terminar o comenzar a la mitad de una palabra, que se encuentra en algún lugar dentro de un trabajo más grande. Estos ocurren naturalmente en todas partes, siendo subconjuntos apropiados de pangramas verdaderos, por lo que solo verificar si algo contiene una ventana pangramática sería aburrido y también se hizo previamente.

Por lo tanto, ¡estamos interesados ​​en encontrar el más pequeño que haya en un texto determinado en función de la longitud de su letra! En el código más corto posible en bytes, por supuesto, para ajustarse al tema.

Reglas y guías

  • Reciba una cadena como entrada y devuelva la cadena de la ventana pangramática más pequeña en la entrada si hay una. Si no lo hay, devuelva un Falso booleano o una cadena vacía.
  • Si una cadena es una ventana pangramática o no distingue entre mayúsculas y minúsculas y solo depende de las 26 letras, no de signos de puntuación o números u otros símbolos impares.
  • Del mismo modo, la longitud de las letras de una ventana pangramática es el número total de la cantidad de apariciones de letras que aparecen solo en ella, y no simplemente el número de cada carácter. El valor devuelto debe ser el más pequeño según este recuento. Somos lingüistas, después de todo, no programadores.
  • Sin embargo, una salida de una ventana pangramática debe ser una subcadena exacta de la entrada, que contenga la misma mayúscula y puntuación, etc.
  • Si hay varias ventanas pangramáticas más cortas de la misma longitud de letra, devuelva cualquiera de ellas.

Casos de prueba

'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
fuente
1
Para el último caso de prueba, ¿por qué no se The five boxing wizards jump quicklydevuelve?
Azul
1
Para el segundo caso, ¿se le permite el espacio que precede al Q? No se suma al recuento de letras.
Neil
2
@muddyfish Porque tiene 31 letras, mientras que la salida esperada solo tiene 26.
Martin Ender
44
Buena primera pregunta!
Rɪᴋᴇʀ
2
Sí. No hay razón para que no sea así. Tomar el mínimo "verdadero" en el espíritu de la pregunta, pero no es necesario.
Reecer6

Respuestas:

6

Pyth, 20 16 14 bytes

hol@GNf!-GrT0.:

Explicación:

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

Pruébalo aquí!

Cuando no hay una solución correcta, el programa sale con un error sin salida a stdout.

Azul
fuente
Parece que no ha actualizado el código en el primer bloque de código. También !-GrT0es más corto para la condición del filtro, creo. También creo que necesitas lpara que el ordenamiento funcione correctamente.
FryAmTheEggman
Oh, hablé mal, me refería al enlace. En tu enlace todavía tienes el l, y sin él obtienes resultados diferentes . Creo que el problema son las letras repetidas, pero no estoy 100% seguro.
FryAmTheEggman
Entonces sí importa, ¡y gracias por la optimización!
Azul
3

Pyth - 22 bytes

\ o / FGITW!

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

Test Suite .

Maltysen
fuente
2

Ruby, 100 bytes

Devuelve nil si no se encuentra ninguna ventana.

->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}
Tinta de valor
fuente
2

JavaScript (ES6), 139 138 136 bytes

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

¡Ahorré 2 bytes gracias a @Neil!

Sangrado

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>

usuario81655
fuente
¿No puedes usar [r=l="",...s].map((_,b,a)=>?
Neil
@Neil Gracias, siempre me olvido del tercer parámetro en la mapfunción.
user81655
Sin embargo, creo que @ edc65 puede vencer esto, fusioné el código de sus subcadenas explotadas con el de su probador de pangramas y terminé con una función de 134 bytes.
Neil
Mi mejor es 142 hasta ahora
edc65
Lamentablemente, no pensé en guardarlo y mi PC se bloqueó, así que ahora no sé lo que tenía; Lo mejor que puedo hacer ahora es 138 bytes.
Neil
2

PowerShell v2 +, 218 bytes

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í, por lo que la manipulación de subcadenas (no hay incorporados) no es realmente el fuerte de PowerShell ...

Tomamos información param($a)y establecemos una nueva tabla hash vacía $z. Este será nuestro almacenamiento de subcadenas pangramáticas candidatas.

Usando una ligera modificación de mi código de Subcadenas explotadas , construimos todas las subcadenas de la entrada. Sí, incluso subcadenas de un solo carácter de puntuación. Este es el , no . ;-)

Todas esas subcadenas se encapsulan en parens y se canalizan a otro bucle con |%{...}. Establecemos temporalmente $ynuestra subcadena actual, establecemos un contador auxiliar $je iniciamos otro ciclo 65..90|%{...}, convenientemente sobre los códigos de caracteres ASCII para letras mayúsculas. Tomamos cada bucle interno, lo ponemos $ytodo en mayúscula y sacamos .IndexOfese char en particular. Como esto regresará -1si no se encuentra, tenemos +1el resultado antes de multiplicarlo en $j. Esto garantiza que si no se encuentra ningún carácter, $jserá igual a cero.

De eso se trata exactamente if. Si $jno es cero, eso significa que cada letra se encontró al menos una vez en la subcadena $y, por lo que debemos agregarla a nuestro grupo de candidatos. Lo hacemos tomando $ye ingiriendo -replacecada no letra sin nada, lo que nos da la longitud de la letra de esa subcadena. Lo usamos como índice en hashtable $zy store$y en ese índice. Esto tiene la peculiaridad de sobrescribir subcadenas de la misma longitud de letra con la que aparece "más lejos" en la cadena original, pero eso está permitido por las reglas, ya que solo nos preocupa la longitud de la letra.

Finalmente, tenemos que clasificar $zy sacar el más pequeño. Tenemos que usar la .GetEnumeratorllamada para ordenar los objetos dentro $z , luego sortlos que están en Name(es decir, el índice de longitud desde arriba), seleccionando el [0]uno (es decir, el más corto) y generando su .Value(es decir, la subcadena). Si no se ajusta dicha subcadena, esto arrojará un error ( Cannot index into a null array) cuando intente $zindexarse ​​y no muestre nada, lo cual es falso en PowerShell. (el tercer caso de prueba a continuación tiene un reparto explícito [bool]para mostrar esto)

Casos de prueba

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
fuente
2

Haskell, 180 bytes

Esto fue difícil, pero realmente divertido sin importaciones.

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]

Mucho menos golfizado:

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: es realmente lento.

Michael Klein
fuente
2

Oracle SQL 11.2, 461 bytes

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;

Sin 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 svista divide la entrada en caracteres y también devuelve la posición de cada carácter.

La vista recursiva vdevuelve cada subcadena de la entrada
s es la subcadena
f la posición del primer carácter de la subcadena
l la posición del último carácter agregado a la subcadena actual

La cvista devuelve el alfabeto, una letra a la vez.

La avista devuelve el alfabeto concatenado como una sola cadena

SELECT s,f,SUM(SIGN(INSTR(LOWER(s),c))
Devuelve para cada subcadena el número de letras distintas presentes en ella
INSTRdevuelve la posición de una letra en la subcadena, 0 si no está presente
SIGNdevuelve 1 si pos> 0, 0 si pos = 0

WHERE x=26
Filtra la subcadena que contiene el alfabeto completo

TRANSLATE(LOWER(s),' '||a,' ')
Elimina todas las letras de la subcadena.

LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')
La longitud en letras es la longitud de la subcadena menos la longitud de la subcadena sin letras

SELECT MIN(s)KEEP(DENSE_RANK FIRST ORDER BY LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')),0))
Mantiene solo la subcadena con el recuento de letras más pequeño.
Si hay más de uno, el primero, ordenado como cadenas ascendentes, se mantiene

Jeto
fuente
2

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

Guardado 4 bytes gracias a DSM.
Guardado 8 bytes gracias 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)))

Tener que ordenar según la cantidad de letras me está matando.

Casos de prueba:

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
fuente
No piense que .upper()es necesario en la función clave.
RootTwo
@RootTwo Oops, sí, tienes razón. Gracias.
Morgan Thrapp
1

PowerShell (v4), 198156 bytes

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]

Casos de prueba

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!

Explicación sin fundamento del original

Es un bucle anidado de fuerza bruta que hace que las ventanas deslizantes de todos los tamaños:

.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

Para cada ventana, filtra solo las letras (coincidencia de expresiones regulares que no distingue entre mayúsculas y minúsculas), ejecuta los caracteres restantes a través de un filtro único, verifica si hay 26 caracteres únicos como prueba de pangrama.

Todas las ventanas con pangramas se convierten en trillizos de (número de letras que incluyen duplicados, índice de inicio, longitud de la ventana que incluye puntuación) , que se ordenan para encontrar el más corto por recuento general de caracteres, el primero se selecciona y la cadena de salida se construye a partir de ese .

Hay una gran cantidad de indexación fuera de los límites de la cadena, que PowerShell devuelve $ nulo, en lugar de generar excepciones.

NÓTESE BIEN. el nuevo 156 byte uno es el mismo enfoque, pero reescrito para usar la tubería mucho más.

$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 ''
}

NÓTESE BIEN. No estoy seguro de que la versión sin golf funcione, porque no escribí eso y luego la golfé, es solo para exposición.

TessellatingHeckler
fuente
0

Haskell, 123 bytes

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

Define una función h, que devuelve la lista vacía si no hay una ventana pangramática o una lista de un elemento con la ventana mínima. Ejemplo de uso:

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

Cómo funciona:

          [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
fuente