Histograma do alfabeto

33

Dada uma frase de entrada que consiste em uma ou mais palavras [a-z]+e zero ou mais espaços , imprima um histograma de arte ASCII (gráfico de barras) da distribuição de letras da frase de entrada.

O histograma deve ser disposto horizontalmente, ou seja, com a tecla da letra na parte inferior, em ordem alfabética da esquerda para a direita, com um eixo Y rotulado 1-e a cada 5 unidades. O eixo Y deve ser o menor múltiplo de cinco que seja pelo menos tão alto quanto a barra mais alta e deve estar alinhado à direita. O eixo X é identificado com as letras de entrada, sem espaços entre eles. Por exemplo, a entrada a bb dddeve ter rótulo abde não ab d, pulando o c. As barras em si podem ser feitas de qualquer caractere ASCII consistente - usarei Xaqui em meus exemplos.

test example

5-

   X
   X   X
1-XXXXXXXX
  aelmpstx

Uma vez que existem três e, dois te um de almsx.

Mais exemplos:

the quick brown fox jumped over the lazy dogs

5-
      X         X
      X         X
     XX  X      X  X XX
1-XXXXXXXXXXXXXXXXXXXXXXXXXX
  abcdefghijklmnopqrstuvwxyz


now is the time for all good men to come to the aid of their country

10-
              X
              X
              X  X
      X       X  X
 5-   X       X  X
      X   X   X  X
      X  XX XXXX X
   XXXXX XXXXXXX X
 1-XXXXXXXXXXXXXXXXXX
   acdefghilmnorstuwy

a bb ccc dddddddddddd

15-


      X
      X
10-   X
      X
      X
      X
      X
 5-   X
      X
     XX
    XXX
 1-XXXX
   abcd

a bb ccccc

5-  X
    X
    X
   XX
1-XXX
  abc

E / S e regras

  • A entrada pode ser obtida em qualquer formato razoável e por qualquer método conveniente . Isso também significa que você pode inserir entradas em maiúsculas, se isso fizer mais sentido para o seu código.
  • Novas linhas à esquerda / à direita ou outro espaço em branco são opcionais, desde que os caracteres sejam alinhados adequadamente.
  • Um programa completo ou uma função são aceitáveis. Se uma função, você pode retornar a saída em vez de imprimi-la.
  • A saída pode ser no console, retornada como uma lista de cadeias, retornada como uma única cadeia, etc.
  • As brechas padrão são proibidas.
  • Isso é portanto todas as regras usuais de golfe se aplicam e o código mais curto (em bytes) vence.
AdmBorkBork
fonte
3
Penso que este seria um gráfico de barras e não um histograma, pois são dados categóricos e não numéricos, mas estou sendo principalmente pedante.
Giuseppe
a entrada é garantida como não vazia?
Dzaima 11/0418
2
Sendo apenas um pingente, mas este não é um histograma , é um gráfico de barras. Ainda é um bom desafio!
você precisa saber é o seguinte
4
Uma abordagem tuftiana seria criar as barras com os caracteres representados e não ter uma linha de rótulo separada.
dmckee
2
O caractere do histograma deve ser consistente, mas entre os casos ou dentro de cada caso?
Adám 12/04/19

Respostas:

7

R , 239 230 bytes

K=table(el(strsplit(gsub(" ","",scan(,"")),"")));m=matrix(" ",L<-sum(K|1)+1,M<-(M=max(K))+-M%%5+1);m[2:L,M]=names(K);m[1,M-g]=paste0(g<-c(1,seq(5,M,5)),"-");m[1,]=format(m[1,],j="r");for(X in 2:L)m[X,M-1:K[X-1]]=0;write(m,1,L,,"")

Experimente online!

table faz o trabalho pesado aqui, unificando os personagens, ordenando-os e retornando suas contagens.

Tudo o resto é apenas garantir que as compensações sejam corretas para impressão, que é o trabalho "real" de um desafio da arte ascii.

Graças a @dylnan por apontar um bug.

Obrigado a @rturnbull pela scanabordagem, eliminando 2 bytes.

Giuseppe
fonte
237 bytes
rturnbull
@rturnbull Consegui derrubar mais alguns bytes depois disso, obrigado!
Giuseppe
6

gnu sed -r, 516 490 278249 + 1 bytes

s/$/:ABCDEFGHIJKLMNOPQRSTUVWXYZ /
:a
s/(.)(:.*\1)/\2\1/I
ta
s/[A-Z]+/ /g
h
z
:b
s/ \w/ /g
G
s/:/&I/g
/:II{5}+ *$/M!bb
s/[a-z]/X/g
G
s/:(I{5}+|I)\b/0\1-/g
s/:I*/  /g
s/ (\w)\1*/\1/g
s/$/; 10123456789I0/
:c
s/(.)I(.*\1(I?.))|;.*/\3\2/
/\nI/s/^/ /Mg
tc

Experimente online!


Estou certo de que isso pode ser melhorado , mas, por enquanto, isso deve ser bom, considerando que é feito no sed, onde você não tem aritmética ou classificação nativas. Então, eu menti, isso não era bom o suficiente, então eu o melhorei (reescrevi) em outros 212 bytes, com uma dica sobre o algoritmo de classificação do charlatão de vacas , o que me deu uma idéia para diminuir a conversão unária para decimal.
Descrição do funcionamento interno:

s/$/:ABCDEFGHIJKLMNOPQRSTUVWXYZ /
:a
s/(.)(:.*\1)/\2\1/I
ta
s/[A-Z]+/ /g
h
z

Isso classifica a entrada e separa os grupos com espaços. Isso funciona anexando primeiro um alfabeto em maiúsculas mais o espaço separado por dois pontos no final. Em seguida, move cada caractere na frente dos dois pontos para um caractere correspondente atrás dos dois pontos usando uma substituição que não diferencia maiúsculas de minúsculas em um loop. As letras maiúsculas são substituídas por espaços e a sequência é copiada para o espaço em espera.

:b
s/ \w/ /g
G
s/:/&I/g
/:II{5}+ *$/M!bb

Esse loop funciona reduzindo o tamanho de cada grupo de caracteres em um, acrescentando a linha original classificada e aumentando os contadores unários após os dois pontos que permaneceram na classificação. Ele faz um loop até que uma linha vazia com um número de 5 * n + 1 seja atingida (uma vez que a última linha resulta em espaço em branco). O espaço do padrão se parece com isso após o loop:

:IIIIII           
:IIIII           
:IIII           
:III  e         
:II  ee     t    
:I a eee l m p s tt x   

A seguir, a formatação:

s/[a-z]/X/g            # makes bars consistent
G                      # appends line that becomes x-axis
s/:(I{5}+|I)\b/0\1-/g  # moves zero in front of line 1 or 5-divisible
                       # lines for the decimal conversion and adds -
s/:I*/  /g             # removes numbers from other lines
s/ (\w)\1*/\1/g        # collapses groups of at least 1 into 1
                       # character, deleting the space before it
                       # so that only size-0-groups have spaces

E, finalmente, o conversor unário para decimal permanece:

s/$/; 10123456789I0/
:c
s/(.)I(.*\1(I?.))|;.*/\3\2/
/\nI/s/^/ /Mg
tc

Ele basicamente anexa uma string onde está o conhecimento da conversão. Você pode interpretá-lo como: espaço: -> 1 e 0-> 1-> 2-> 3-> 4-> 5-> 6-> 7-> 8-> 9-> 10. A expressão de substituição s/(.)I(.*\1(I?.))|;.*/\3\2/funciona de maneira semelhante à da classificação, substituindo os caracteres na frente de I's [ (.)I] pelo caractere que fica ao lado da frente da I na seqüência de conversão [ (.*\1(I?.))] e, se não houver mais, ele remove a sequência anexada [ |;.*]. A substituição [ /\nI/s/^/ /Mg] adiciona preenchimento, se necessário.

Agradecimentos ao vacas charlatão por reduzir o tamanho em 26 bytes e pelo algoritmo de classificação mais curto.

Sad Sed
fonte
Bem-vindo ao PPCG e boa primeira resposta!
Kritixi Lithos
Você pode usar \w(corresponde aos caracteres da palavra) em vários locais para salvar alguns bytes. Também :b ... tbpode simplesmente se tornar s/\B\w/X/g. Você pode remover a linha que se segue s/:/:,/g, modificando as substituições anteriores. Você pode olhar em goo.gl/JvD7Rs (link TIO reduzido para o programa sed) para ver o que quero dizer.
Kritixi Lithos
1
Você pode melhorar o algoritmo de classificação, dica: tente anexar zyx...cbaà entrada.
precisa saber é o seguinte
Conversor unário para decimal brilhante! O seu é, pelo menos, 30 bytes menor do que o de dicas para golfe em sed
Kritixi Lithos
5

Dyalog APL , 109 97 96 95 93 88 bytes

{⊖(⍉r),⍨⍕↑(⊂'')@{1@0~⍵∊1,5×⍵}⍳≢⍉↑r←↑r,⍨⊂' -','   - '⍴⍨5×⌈5÷⍨≢1↓⍉↑r←↓{⍺,∊⍕¨0×⍵}⌸⍵[⍋⍵]∩⎕A}

Experimente online!

Requer ⎕IO←0

Way muitos bytes salvos graças a Adám e Vacas quack !

dzaima
fonte
Para o último bit, você pode tentar ⍵[⍋⍵]~' '(os tipos e remove espaços antes de passar através )
Kritixi Lithos
'X'/⍨≢∊⍕¨×
Adám
e ⍵>0×⍵
Kritixi Lithos
Seu link TIO possui um cabeçalho desnecessário.
Adám 11/04/19
2⌷⍴≢⍉duas vezes
Adám 11/04/19
5

05AB1E , 58 47 bytes

áê©S¢Z5‰`Ā+L5*1¸ì'-«ð5×ý#À¦Áí.Bís'X×ζ‚ζJR»,®3ú,

Experimente online!

-11 bytes graças a @Emigna

Urna de polvo mágico
fonte
Talvez isso possa ajudar? Não tenha tempo para amarrá-los, mas talvez eles possam dar alguma inspiração.
Emigna
@ Emigna, vou dar uma olhada, definitivamente diferente da minha :).
Magic Octopus Urn
@ Emigna 57 bytes depois de o ter costurado ... dado que não tentei otimizar muito. Experimente online!
Magic Octopus Urn
47 bytes com alguma reestruturação e otimização.
Emigna
Suas letras não estão alinhadas com os X para determinadas entradas. tio.run/##AVUAqv8wNWFiMWX//...
mbomb007
3

Python 2 , 192 bytes

s=input()
d={c:s.count(c)for c in s if' '<c}
h=-max(d.values())/5*-5
for y in range(h,-1,-1):print('%d-'%y*(y%5==2>>y)).rjust(len(`-h`))+''.join(('X '[y>v],k)[y<1]for k,v in sorted(d.items()))

Experimente online!

Explicação

A linha 2 calcula os valores do histograma de maneira bastante direta, descartando ' '.

A linha 3 usa o truque da computação ceil(x/5)como -(-x/5): arredondamos a frequência máxima até o próximo múltiplo de 5 usando a fórmula -x/5*-5. Isto é h.

A linha 4 é um loop que conta de hbaixo a 0inclusivo, imprimindo cada linha:

  • Se y%5==2>>yimprimirmos uma etiqueta. É quando y∈ {1, 5, 10, 15, 20,…}

    (Essa fórmula pode ser mais curta. Precisamos apenas de 1 ou Verdadeiro para {1, 5, 10,…} e 0 ou Falso ou até mesmo um número inteiro negativo para todos os outros valores de y.)

  • Justificamos à direita o rótulo (ou espaço vazio) em len(`-h`)espaços: é uma economia de um byte pura len(`h`)+1!

  • Em seguida, imprimimos Xespaços e espaços para esta linha (se y≥ 1) ou as letras (se y= 0), percorrendo pares de valores-chave dem ordem crescente.

Lynn
fonte
1
Criação de carrapatos agradável com '%d-'%y*(y%5==2>>y). Você se importa se eu usar isso na minha resposta?
dylnan
-~-(y%5*~-y)funciona também, mas infelizmente é um byte a mais.
dylnan
2

Carvão , 62 bytes

≔E²⁷⟦⟧ηFθ⊞§η⌕βιι≔⊟ηθ≦LηP⭆β⎇§ηκιω↑↑ΦηιF÷⁺⁹⌈η⁵«≔∨×⁵ι¹ιJ±¹±ι←⮌⁺ι-

Experimente online! Link é a versão detalhada do código. Explicação:

≔E²⁷⟦⟧η

Crie uma lista de 27 listas.

Fθ⊞§η⌕βιι

Empurre cada caractere de entrada para a lista correspondente à sua posição no alfabeto minúsculo. Caracteres não minúsculos são enviados para a 27ª lista.

≔⊟ηθ

Descarte o 27º elemento da lista.

≦Lη

Pegue os comprimentos de todos os elementos da lista.

P⭆β⎇§ηκιω

Imprima as letras minúsculas correspondentes aos elementos da lista diferentes de zero.

↑↑Φηι

Imprima os elementos da lista diferentes de zero para cima. Como essa é uma matriz de números inteiros, cada número inteiro é impresso como uma linha (agora vertical), cada um em uma coluna separada.

F÷⁺⁹⌈η⁵«

Calcule o número de marcas de verificação no eixo Y e faça um loop sobre elas.

≔∨×⁵ι¹ι

Calcule a posição da próxima marca de seleção.

J±¹±ι

Pule para a próxima marca.

←⮌⁺ι-

Imprima a marca de ré invertida e de trás para frente, alinhando-a efetivamente com a direita.

Neil
fonte
2

Gelatina , 48 bytes

Que campo minado para atravessar!

J’⁶D;”-Ɗ%5^ỊƲ?€Uz⁶ZU
ḟ⁶ṢµĠ¬;⁶$L%5Ɗ¿€;"@Qz⁶Ç;"$ṚY

Um programa completo imprimindo o resultado (como um link monádico, ele retornaria uma lista contendo caracteres e números inteiros de [0,9])

Experimente online! Ou veja a suíte de testes

Quão?

J’⁶D;”-Ɗ%5^ỊƲ?€Uz⁶ZU - Link 1, get y-axis: list of columns (including x-axis & top-spaces)
J                    - range of length  [1,2,3,4,5,6,...,height+1] (+1 for x-axis)
 ’                   - decrement        [0,1,2,3,4,5,...] (line it up with the content)
             ?€      - if for €ach...
            Ʋ        - ...condition: last four links as a monad:
        %5           -   modulo by five
           Ị         -   insignificant? (1 for 0 and 1, else 0)
          ^          -   XOR (0 for 1 or multiples of 5 greater than 0, else 0)
  ⁶                  - ...then: literal space character
       Ɗ             - ...else: last three links as a monad:
   D                 -   decimal list of the number, e.g. 10 -> [1,0]
     ”-              -   literal '-' character
    ;                -   concatenate, e.g. [1,0,'-']
               U     - upend (reverse each)
                z⁶   - transpose with a filler of space characters
                  Z  - transpose
                   U - upend (i.e. Uz⁶ZU pads the left with spaces as needed)

ḟ⁶ṢµĠ¬;⁶$L%5Ɗ¿€;"@Qz⁶Ç;"$ṚY - Main link: list of characters
ḟ⁶                          - filter out space characters
  Ṣ                         - sort
   µ                        - start a new monadic chain, call that S
    Ġ                       - group indices of S by their values
     ¬                      - logical NOT (vectorises) (getting 0 for the X "characters")
             ¿€             - while for €ach...
            Ɗ               - ...condition: last three links as a monad:
         L                  -   length
          %5                -   modulo by five
        $                   - ...do: last two links as a monad:
      ;⁶                    -   concatenate a space character
                  Q         - deduplicate S (get the x-axis)
               ;"@          - zip with (") concatenation (;) with swapped arguments (@)
                   z⁶       - transpose a with filler of space characters
                        $   - last two links as a monad:
                     Ç      -   call last link (1) as a monad (get y-axis)
                      ;"    -   zip with concatenation (complete the layout)
                         Ṛ  - reverse (otherwise it'll be upside-down)
                          Y - join with newlines
                            - implicit print
Jonathan Allan
fonte
2

Ruby , 250 248 234 188 173 157 153 bytes

->s{a=s.scan(/\w/).sort|[]
m=-(c=a.map{|l|s.count l}).max/5*-5
m.downto(1).map{|i|(i%5<1||i<2?"#{i}-":'').rjust(m)+c.map{|l|l<i ?' ':?X}*''}<<' '*m+a*''}

Experimente online!

Graças a:

  • dylnan para -16 bytes com preenchimento menos rigoroso
  • Lynn para -2 bytes, arredondando para cima com-x/5*-5
  • Kirill L. por -2 bytes, obtendo elementos únicos do array com|[]
Nnnes
fonte
2

Java (JDK 10) , 296 bytes

s->{int d[]=new int[26],m=0;char a;for(int c:s.getBytes())m=c>32&&++d[c-=65]>m?(d[c]+4)/5*5:m;String r=m+"-",z=r.replaceAll("."," ");for(;m>0;r+="\n"+(--m%5<1|m==1&&m>0?z.format("%"+~-z.length()+"s-",m):z))for(a=0;a<26;a++)r+=d[a]>0?m>d[a]?" ":"x":"";for(a=64;a++<90;)r+=d[a-65]>0?a:"";return r;}

Experimente online!

Créditos

Olivier Grégoire
fonte
@aoemica Correto. Eu consertei isso.
Olivier Grégoire
1
Não é muito, mas você pode salvar 2 bytes. --m%5==0pode ser --m%5<1, porque você também tem o &m>0cheque. E m<=d[a]?"x":" "pode ser m>d[a]?" ":"x".
Kevin Cruijssen 12/04/19
@KevinCruijssen 2 bytes são 2 bytes! Acho que não há muito mais para jogar golfe, exceto por um algoritmo diferente.
Olivier Grégoire
1
Mais 1 byte, alterando (--m%5<1|m==1)&m>0para--m%5<1|m==1&&m>0
Kevin Cruijssen
1

Pitão, 65 bytes

J.tm+ed*hd\Xr8S-Qd)=+J*]d%_tlJ5_.e+?q<k2%k5.F"{:{}d}-",klQ*dhlQbJ

Experimente aqui

Explicação

J.tm+ed*hd\Xr8S-Qd)=+J*]d%_tlJ5_.e+?q<k2%k5.F"{:{}d}-",klQ*dhlQbJ
J.tm+ed*hd\Xr8S-Qd)
     Get the bars.
                   =+J*]d%_tlJ5
     Round up the height to the next number that's 1 mod 5.
                               _.e+?q<k2%k5.F"{:{}d}-",klQ*dhlQbJ
     Stick the axis labels on.

fonte
1

JavaScript (Node.js) , 262 256 bytes

* Obrigado a @Shaggy por reduzir em 2 bytes

a=>[...a].map(x=>x>" "&&(d=c[x]=(c[x]||x)+"X")[m]?m=d.length-1:0,c={},m=i=0)&&Object.keys(c).sort().map(x=>[...c[x].padEnd(m)].map((l,j)=>A[m-j-1]+=l),A=[...Array(m+=6-m%5)].map(x=>(++i>=m||((D=m-i)%5&&m-i^1)?"":D+"-").padStart((m+" ").length)))&&A.join`
`

Experimente online!

DanielIndie
fonte
Algumas economias rápidas que posso encontrar no meu telefone: 1.aceite as entradas como uma variedade de caracteres individuais, 2.Substitua x!=" "por x>" ".
Shaggy
3.Substitua m=0por i=m=0e map((x,i)=>com map(x=>.
Shaggy
1

Python 2 , 249 224 219 215 205 197 187 188 182 176 bytes

def f(s):S=sorted(set(s)^{' '});C=map(s.count,S);P=max(C)+4;return zip(*(zip(*[('%d-'%y*(y%5==2>>y)).rjust(P)for y in range(P,0,-1)])+[(n*'#').rjust(P)for n in C]))+[[' ']*P+S]

Experimente online!

Retorna uma lista de listas de caracteres que representam linhas.

  • Economizou alguns bytes incluindo muito espaço em branco extra.
  • Teve um desnecessário map(list,yticks)lá.
  • Preenchimento de espaço alterado para salvar alguns bytes.
  • Eu pensei que estava classificando, mas não estava: +2 bytes. Mas eu salvei um independentemente ao mesmo tempo. y==1substituído por y<2.
  • -6 bytes graças ao Lynn usando em '%d-'%y*(y%5==2>>y)vez de (`y`+'-')*(not y%5or y<2).

Ligeiramente não destruído:

def f(s):
	S=sorted(set(s)^{' '})  # sorted list of unique letters (without ' ')
	C=map(s.count,S)        # count of each unique letter in the input
	P=max(C)+4              # used for padding and getting highest y tick
	B=[(n*'#').rjust(P)for n in C]     # create bars
	yticks = [('%d-'%y*(y%5==2>>y)).rjust(P)for y in range(P,0,-1)]  # create y ticks at 1 and multiples of 5
	yticks = zip(*yticks)                      # need y ticks as columns before combining with bars
	return zip(*(yticks+B))+[[' ']*P+S]        # zip ticks+bars then add row of sorted unique letters.
dylnan
fonte
1

C # (.NET Core) , 344 340 338 + 18 bytes

Inclui 18 bytes para using System.Linq;

Guardado 6 bytes graças a @KevinCruijssen.

n=>{var l=n.Where(c=>c!=32).GroupBy(c=>c).OrderBy(c=>c.Key).ToDictionary(k=>k.Key,c=>c.Count());int h=(l.Values.Max()/5+1)*5,o=(h+"").Length+1,m=l.Keys.Count+o,t=h+1,i=0,j;var a=new string[t];for(string p,q;i<t;a[i++]=q)for(q=(p=i>0&i%5<1|i==1?i+"-":"").PadLeft(j=o);j<m;){var c=l.ElementAt(j++-o).Key;q+=i<1?c:l[c]>=i?'X':' ';}return a;}

Experimente online!

Ian H.
fonte
Você tem um espaço j< m;que pode ser removido. E int i=0,jpode ser colocado como ,i=0,japós as outras entradas para -4 bytes no total. Você precisará incluir os 18 bytes para ousing System.Linq; no entanto ..
Kevin Cruijssen
@KevinCruijssen Obrigado, eu perdi esses. E eu adicionei os 18 bytes.
Ian H.
+1 de mim. Ah, e você pode salvar mais 2 bytes alterandofor(;i<t;){string p=i>0&i%5<1|i==1?i+"-":"",q=p.PadLeft(o);for(j=o;j<m;){...}a[i++]=q;} para for(string p,q;i<t;)for(p=i>0&i%5<1|i==1?i+"-":"",q=p.PadLeft(j=o);j<m;a[i++]=q){...}. Experimente online.
Kevin Cruijssen 13/04/19
@KevinCruijssen Isso é realmente inteligente, obrigado!
Ian H.
1

Bash + coreutils, 332 324 323 318 312 302 298 296 293 291 bytes

c()(cut -d\  -f$@)
p=printf
cd `mktemp -d`
grep -o [^\ ]<<<$@|sort|uniq -c|c 7->a
sort -k2<a>b
r=$[`c 1 <a|sort -n|tail -1`+5]
s=${#r}
t()($p \ ;((i++<s))&&t;i=)
for((;--r;));{
((r%5&&r>1))&&t||$p %${s}s- $r;IFS='
'
for l in `<b`;{ ((r<=`c 1 <<<$l`))&&$p X||$p \ ;}
echo
}
t
c 2 <b|tr -d \\n

Experimente online!

Anotado:

c()(cut -d\  -f$@)
p=printf              # saving a few bytes

cd `mktemp -d`        # for temp files

grep -o [^\ ]<<<$@    # grabs all non-space characters
    |sort|uniq -c     # get character frequency
    |c 7->a           # slightly hacky way of stripping leading spaces;
                      #     uniq -c adds 6 spaces in front of each line

sort -k2<a>b          # store frequencies sorted alphabetically in b

r=$[`                 # r = highest frequency +5:
    c 1 <a            #     get frequencies
    |sort -n|tail -1  #     get maximum frequency
    `+5]              #     +4 so at least one multiple of 5 is
                      #     labeled, +1 because r gets pre-decremented

s=${#r}                    # s = length of r as a string
t()($p \ ;((i++<s))&&t;i=) # pad line with s+1 spaces

for((;--r;));{         # while (--r != 0)
    ((r%5&&r>1))&&     # if r isn't 1 or a multiple of 5
        t||            #     then indent line 
        $p %${s}s- $r; # otherwise print right-aligned "${r}-"
        IFS='
'                      # newline field separator
    for l in `<b`;{          # for all letters and their frequencies:
        ((r<=`c 1 <<<$l`))&& #     if frequency <= current height 
            $p X||           #         then print an X
            $p \ ;}          #     otherwise print a space
    echo
}
t # indent x-axis labels
c 2 <b|tr -d \\n # print alphabetically sorted characters

Obrigado a @IanM_Matrix por salvar 3 bytes.

user9549915
fonte
cat bpoderia estar <bsalvando 3 caracteres
IanM_Matrix1
0

C, 201 bytes

char c[256],*p,d;main(int a,char **b){for(p=b[1];*p;p++)++c[*p|32]>d&*p>64?d++:0;for(a=(d+4)/5*5;a+1;a--){printf(!a||a%5&&a!=1?"    ":"%3i-",a);for(d=96;++d>0;c[d]?putchar(a?32|c[d]>=a:d):0);puts(p);}}

A entrada é obtida da linha de comando (primeiro argumento). Usa pontos de exclamação em vez de Xs para reduzir ainda mais o tamanho do código. O contador à esquerda tem sempre três caracteres.

Testado com GCC e clang.

Simon
fonte
for(p=b[1];*p;p++)provavelmente pode ser for(p=b[1]-1;*++p;), main(int a,char **b)provavelmente poderia ser jogado para m(a,b)char**b;.
11138 Jonathan Frech
Como a!=1será booleano, a%5&&a!=1?deve ser equivalente a a%5&a!=1?ou a%5&&~-a.
11138 Jonathan Frech
0

Excel VBA, 316 bytes

Uma função de janela imediata do VBE anônimo que recebe entrada da célula [A1]e sai para a janela imediata do VBE.

For i=1To 26:Cells(2,i)=Len(Replace([Upper(A1)],Chr(i+64),11))-[Len(A1)]:Next:m=-5*Int(-[Max(2:2)]/5):l=Len(m)+1:For i=-m To-1:?Right(Space(l) &IIf(i=-1Xor i Mod 5,"",-i &"-"),l);:For j=1To 26:?IIf(Cells(2,j),IIf(Cells(2, j) >= -i, "X", " "),"");:Next:?:Next:?Spc(l);:For i=1To 26:?IIf(Cells(2,i),Chr(i+96),"");:Next

Versão Ungolfed

Public Sub bar_graph()
    For i = 1 To 26
        ''  gather the count of the letter into cells
        Cells(2, i) = Len(Replace([Upper(A1)], Chr(i + 64), 11)) - [Len(A1)]
    Next
    m = -5 * Int(-[Max(2:2)] / 5)   ''  get max bar height
    l = Len(m) + 1                  ''  length of `m` + 1
    For i = -m To -1
        ''  print either a label or free space (y-axis)
        Debug.Print Right(Space(l) & IIf((i = -1) Xor i Mod 5, "", -i & "-"), l);
        For j = 1 To 26
            ''  print 'X' or ' ' IFF the count of the letter is positive
            If Cells(2, j) Then Debug.Print IIf(Cells(2, j) >= -i, "X", " ");
        Next
        Debug.Print                 ''  print a newline
    Next
    Debug.Print Spc(l);             ''  print spaces
    For i = 1 To 26
        ''  print the letters that were used (x-axis)
        Debug.Print IIf(Cells(2, i), Chr(i + 96), "");
    Next
End Sub
Taylor Scott
fonte
0

Perl 5 -n , 198 168 bytes

s/[a-z]/$\<++${$&}?$\=${$&}:0/eg;$\++while$\%5;$;=1+length$\++;printf"%$;s".'%s'x26 .$/,$\%5&&$\-1?"":"$\-",map$$_>=$\?X:$$_&&$",a..z while--$\;say$"x$;,map$$_&&$_,a..z

Experimente online!

Xcali
fonte
0

Python 3 , 177 bytes

lambda s:[[list(("%d-"%i*(i%5==2>>i)).rjust(len(q)))+["* "[s.count(c)<i]for c in q]for i in range(max(map(s.count,q))+4,0,-1)]+[[" "]*len(q)+q]for q in[sorted(set(s)-{' '})]][0]

Experimente online!

Essa pode não ser a abordagem mais eficiente em bytes em Python, mas eu realmente queria resolver isso com uma lambda "true one-liner".

Produz uma lista de listas de caracteres. Abusa de várias novas linhas e espaços principais, como todo mundo. Na verdade, pode ser ainda mais reduzido para 174 bytes se for aceitável agrupar o resultado em outra lista, para que possamos transferir a [0]indexação final para o rodapé.

Kirill L.
fonte
0

JavaScript (ES8), 200 bytes

Recebe a entrada como uma matriz de caracteres. Retorna uma string.

s=>(s.sort().join``.replace(/(\w)\1*/g,s=>a.push(s[0]+'X'.repeat(l=s.length,h=h<l?l:h)),h=a=[]),g=y=>y--?(y<2^y%5?'':y+'-').padStart(`${h}_`.length)+a.map(r=>r[y]||' ').join``+`
`+g(y):'')(h+=5-~-h%5)

Experimente online!

Comentado

s => (                    // s[] = input array of characters (e.g. ['a','b','a','c','a'])
  s.sort()                // sort it in lexicographical order (--> ['a','a','a','b','c'])
  .join``                 // join it (--> 'aaabc')
  .replace(/(\w)\1*/g,    // for each run s of consecutive identical letters (e.g. 'aaa'):
    s => a.push(          //   push in a[]:
      s[0] +              //     the letter, which will appear on the X-axis
      'X'.repeat(         //     followed by 'X' repeated L times
        L = s.length,     //     where L is the length of the run (--> 'aXXX')
        h = h < L ? L : h //     keep track of h = highest value of L
    )),                   //   initialization:
    h = a = []            //     h = a = empty array (h is coerced to 0)
  ),                      // end of replace() (--> a = ['aXXX','bX','cX'] and h = 3)
  g = y =>                // g = recursive function taking y
    y-- ?                 //   decrement y; if there's still a row to process:
      (                   //     build the label for the Y-axis:
        y < 2 ^ y % 5 ?   //       if y != 1 and (y mod 5 != 0 or y = 0):
          ''              //         use an empty label
        :                 //       else:
          y + '-'         //         use a mark
      ).padStart(         //     pad the label with leading spaces,
        `${h}_`.length    //     using the length of the highest possible value of y
      ) +                 //     (padStart() is defined in ECMAScript 2017, aka ES8)
      a.map(r => r[y]     //     append the row,
                 || ' ')  //     padded with spaces when needed
      .join`` + `\n` +    //     join it and append a linefeed
      g(y)                //     append the result of a recursive call
    :                     //   else:
      ''                  //     stop recursion
)(h += 5 - ~-h % 5)       // call g() with h adjusted to the next multiple of 5 + 1
Arnauld
fonte