Janela Pangramática Mais Curta

15

Um pangram é uma frase ou trecho que contém todas as 26 letras do alfabeto, conforme demonstrado neste desafio de golfe com código . No entanto, uma janela pangramática é um pangram na forma de algum segmento de texto, que pode terminar ou começar no meio de uma palavra, encontrada em algum lugar de um trabalho maior. Estes ocorrem naturalmente em todos os lugares, sendo subconjuntos adequados de pangramas verdadeiros; portanto, apenas verificar se algo contém uma janela pangramática seria chato e também foi feito anteriormente.

Portanto, estamos interessados ​​em encontrar o menor em um determinado pedaço de texto com base no tamanho da letra! No menor código possível em bytes, é claro, para se ajustar ao tema.

Regras e Diretrizes

  • Receba uma string como entrada e retorne a string da menor janela pangramática da entrada, se houver uma. Se não houver, retorne um Boolean False ou uma string vazia.
  • Se uma sequência é uma janela pangramática ou não faz distinção entre maiúsculas e minúsculas e depende apenas das 26 letras, não de qualquer pontuação ou número ou outro símbolo ímpar.
  • Da mesma forma, o tamanho das letras de uma janela pangramática é o número total de quantas aparências de letras ocorrem somente nela, e não simplesmente o número de cada caractere. O valor retornado deve ser menor com base nessa contagem. Afinal, somos linguistas, não programadores.
  • Uma saída de uma janela pangramática deve, no entanto, ser uma substring exata da entrada, contendo a mesma capitalização e pontuação, etc.
  • Se houver várias janelas pangramáticas mais curtas do mesmo tamanho de letra, retorne qualquer uma delas.

Casos de teste

'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
fonte
1
Para o último caso de teste, por que não é The five boxing wizards jump quicklyretornado?
Azul
1
Para o segundo caso, você tem permissão para o espaço que precede o Q? Não adiciona à contagem de letras.
Neil
2
@muddyfish Porque tem 31 letras, enquanto a saída esperada tem apenas 26.
Martin Ender
4
Boa primeira pergunta!
Rɪᴋᴇʀ
2
Sim. Não há razão para não ser. Tomando o mínimo "verdadeiro" no espírito da pergunta, mas não é necessário.
Reecer6

Respostas:

6

Pitão, 20 16 14 bytes

hol@GNf!-GrT0.:

Explicação:

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

Experimente aqui!

Quando não há uma solução correta, o programa sai com um erro sem saída para stdout.

Azul
fonte
Você parece não ter atualizado o código no primeiro bloco de código. Também !-GrT0é mais curto para a condição do filtro, acredito. Também acho que você precisa fazer lcom que a classificação funcione corretamente.
FryAmTheEggman 17/05
Ah, eu errei, eu quis dizer o link. No seu link você ainda tem o l, e sem ele você obtém resultados diferentes . Acredito que o problema sejam cartas repetidas, mas não tenho 100% de certeza.
FryAmTheEggman 17/05
Então isso importa - e obrigado pela otimização!
Azul
3

Pitão - 22 bytes

\ o / FGITW!

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

Conjunto de Teste .

Maltysen
fonte
2

Ruby, 100 bytes

Retorna nulo se nenhuma janela for encontrada.

->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}
Value Ink
fonte
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

Economizou 2 bytes graças a @Neil!

Recuado

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
fonte
Você não pode usar [r=l="",...s].map((_,b,a)=>?
Neil
@ Neil Obrigado, eu sempre esqueço o terceiro parâmetro na mapfunção.
User81655 17/05
Acho que o @ edc65 pode superar isso, mesclei o código para suas substrings explodidas com o do testador de pangram e acabei com uma função de 134 bytes.
Neil
Meu melhor é 142 até agora
edc65 17/05
Infelizmente, não pensei em salvá-lo e meu PC travou, agora não sei o que tinha; o melhor que posso fazer agora é 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

Sim, então a manipulação de substring (não há embutidos) não é realmente o ponto forte do PowerShell ...

Nós recebemos informações param($a)e definimos uma nova hashtable vazia $z. Este será o nosso armazenamento de substratos pangramáticos candidatos.

Usando uma ligeira modificação do meu código de Exploded Substrings , construímos todas as substrings da entrada. Sim, mesmo substrings de pontuação com apenas um caractere. Isso é , não . ;-)

Todas essas substrings são encapsuladas em parênteses e canalizadas para outro loop com |%{...}. Definimos temporariamente $ya nossa substring atual, definimos um contador auxiliar $je iniciamos outro loop 65..90|%{...}, convenientemente sobre os códigos de caracteres ASCII para letras maiúsculas. Cada loop interno, pegamos, colocamos $ytudo em maiúsculas e puxamos o .IndexOfcaractere específico. Como isso retornará -1se não for encontrado, obtemos +1o resultado antes de multiplicá-lo $j. Isso garante que, se algum caractere não for encontrado, $jserá igual a zero.

Qual é exatamente o que o if se trata. Se $jfor diferente de zero, significa que todas as letras foram encontradas pelo menos uma vez na substring $y; portanto, precisamos adicioná-las ao nosso pool de candidatos. Fazemos isso pegando $ye -replacenão cada letra que não seja nada, o que nos dá o tamanho da letra dessa substring. Usamos isso como índice em hashtable $ze armazenamos$y nesse índice. Isso tem a peculiaridade de substituir substrings do mesmo tamanho de letra pelo que ocorre "mais longe" na string original, mas isso é permitido pelas regras, pois estamos preocupados apenas com o tamanho da letra.

Finalmente, precisamos classificar $ze extrair o menor. Temos que usar a .GetEnumeratorchamada para classificar os objetos dentro $z , entãosort os ativados Name(ou seja, o índice de comprimento acima), selecionando o [0]primeiro (ou seja, o mais curto) e exibindo seu .Value(ou seja, a substring). Se nenhuma substring se encaixar, isso gerará um erro ( Cannot index into a null array) ao tentar indexar $ze não produzir nada, o que é falso no PowerShell. (o terceiro caso de teste abaixo tem um elenco explícito [bool]para mostrar isso)

Casos de teste

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

Haskell, 180 bytes

Isso foi difícil, mas muito divertido sem importações.

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]

Muito menos golfe:

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

Surpresa, surpresa: é muito lento.

Michael Klein
fonte
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;

Sem golfe

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

o s exibição divide a entrada em caracteres e também retorna a posição de cada caractere.

A vista recursiva vretorna cada substring da entrada
s é o substring
da posição do primeiro caractere do substring
l a posição do último caractere adicionado ao substring atual

A cexibição retorna o alfabeto, uma letra de cada vez

A aexibição retorna o alfabeto concatenado como uma única sequência

SELECT s,f,SUM(SIGN(INSTR(LOWER(s),c))
Retorna para cada substring o número de letras distintas presentes,
INSTRretorna a posição de uma letra na substring, 0 se não estiver presente,
SIGNretorna 1 se pos> 0, 0 se pos = 0

WHERE x=26
Filtra a substring que contém o alfabeto inteiro

TRANSLATE(LOWER(s),' '||a,' ')
Exclui todas as letras da substring

LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')
Comprimento em letras é o comprimento da substring menos o comprimento da subtring sem letras

SELECT MIN(s)KEEP(DENSE_RANK FIRST ORDER BY LENGTH(s)-NVL(LENGTH(TRANSLATE(LOWER(s),' '||a,' ')),0))
Mantém apenas a substring com a contagem menor de letras.
Se houver mais de um, o primeiro, classificado como cadeias ascendentes, é mantido

Jeto
fonte
2

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

Economizou 4 bytes graças ao DSM.
Economizou 8 bytes graças ao 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)))

Ter que classificar com base no número de letras está me matando.

Casos de teste:

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
fonte
Não pense que .upper()é necessário na função principal.
RootTwo
@RootTwo Opa, sim, você está certo. Obrigado.
Morgan Thrapp
1

PowerShell (v4), 198 156 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 teste

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!

Explicação ungolfed do original

É um loop aninhado de força bruta que cria janelas deslizantes de todos os tamanhos:

.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 janela, ele filtra apenas as letras (correspondência sem distinção entre maiúsculas e minúsculas por padrão), executa os caracteres restantes por meio de um filtro exclusivo, verifica se há 26 caracteres únicos no teste do pangram.

Todas as janelas com pangramas são transformadas em trigêmeos de (número de letras incluindo dupes, índice inicial, comprimento da janela incluindo pontuação) , que são classificadas para encontrar o menor número total de caracteres, o primeiro é escolhido e a sequência de saída criada a partir disso .

Há muita indexação fora dos limites da string, para a qual o PowerShell retorna útil $ null, em vez de lançar exceções.

NB o novo 156 bytes é a mesma abordagem, mas reescrito para usar o pipeline muito mais.

$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 não sei se a versão não-gasta funciona, porque eu não escrevi isso e depois joguei, é apenas para exposição.

TessellatingHeckler
fonte
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 uma função hque retorna a lista vazia se não houver janela pangramática ou uma lista de um elemento com a janela mínima. Exemplo 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"]

Como 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
fonte