alfabeto del histograma

33

Dada una oración de entrada que consta de una o más palabras [a-z]+y cero o más espacios , genera un histograma de arte ASCII (gráfico de barras) de la distribución de letras de la oración de entrada.

El histograma debe presentarse horizontalmente, es decir, con la tecla de letra a lo largo de la parte inferior en orden alfabético de izquierda a derecha, con un eje Y etiquetado 1-y cada 5 unidades. El eje Y debe ser el múltiplo más pequeño de cinco que sea al menos tan alto como la barra más alta, y debe estar alineado a la derecha. El eje X está etiquetado con las letras de entrada, sin espacios entre ellas. Por ejemplo, la entrada a bb dddebe tener etiqueta abdy no ab d, omitiendo c. Las barras en sí pueden estar hechas de cualquier carácter ASCII coherente; lo usaré Xaquí en mis ejemplos.

test example

5-

   X
   X   X
1-XXXXXXXX
  aelmpstx

Como hay tres e, dos ty uno de almsx.

Más ejemplos:

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 y reglas

  • La entrada puede tomarse en cualquier formato razonable y por cualquier método conveniente . Esto también significa que puede tomar la entrada en mayúsculas, si eso tiene más sentido para su código.
  • Las nuevas líneas iniciales / finales u otros espacios en blanco son opcionales, siempre que los caracteres se alineen adecuadamente.
  • Un programa completo o una función son aceptables. Si es una función, puede devolver el resultado en lugar de imprimirlo.
  • La salida puede ser a la consola, devuelta como una lista de cadenas, devuelta como una sola cadena, etc.
  • Las lagunas estándar están prohibidas.
  • Este es el por lo que se aplican todas las reglas habituales de golf, y gana el código más corto (en bytes).
AdmBorkBork
fuente
3
Creo que esto sería un gráfico de barras en lugar de un histograma, ya que es categórico en lugar de datos numéricos, pero en su mayoría estoy siendo pedante.
Giuseppe
¿Se garantiza que la entrada no esté vacía?
dzaima
2
Solo por ser un colgante, pero esto no es un histograma , es un gráfico de barras. Sin embargo, sigue siendo un buen desafío!
caird coinheringaahing
44
Un enfoque tuftiano sería hacer las barras de los caracteres representados y no tener una fila de etiquetas separada.
dmckee
2
El carácter del histograma tiene que ser coherente, pero en todos los casos o dentro de cada caso.
Adám

Respuestas:

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,,"")

Pruébalo en línea!

table hace el trabajo pesado aquí, descalificando a los personajes, clasificándolos y devolviendo sus cuentas.

Todo lo demás es solo garantizar que las compensaciones sean adecuadas para la impresión, que es el trabajo "real" de un desafío de arte ascii.

Gracias a @dylnan por señalar un error.

Gracias a @rturnbull por el scanenfoque, dejando caer 2 bytes.

Giuseppe
fuente
237 bytes
rturnbull
@rturnbull Logré eliminar algunos bytes más después de eso, ¡gracias!
Giuseppe
6

gnu sed -r, 516 490 278 249 + 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

Pruébalo en línea!


Estoy seguro de que esto se puede mejorar , pero por ahora, esto debería ser bueno teniendo en cuenta que está hecho en sed, donde no tienes aritmética ni clasificación nativas. Así que mentí, esto no era lo suficientemente bueno, así que lo mejoré (reescribí) en otros 212 bytes, con un consejo sobre el algoritmo de clasificación de Cows quack , que me dio la idea de hacer que la conversión de unario a decimal también sea más corta.
Descripción del funcionamiento interno:

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

Esto ordena la entrada y separa los grupos con espacios. Esto funciona agregando primero un alfabeto en mayúscula más un espacio separado por dos puntos al final. Luego, mueve cada personaje delante del colon a un personaje coincidente detrás del colon usando una sustitución insensible a mayúsculas y minúsculas en un bucle. Las letras mayúsculas se reemplazan por espacios y la cadena se copia en el espacio de espera.

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

Este bucle funciona reduciendo el tamaño de cada grupo de caracteres en uno, agregando la línea original ordenada e incrementando los contadores unarios después de los dos puntos que quedaron de la clasificación. Se repite hasta que se alcanza una línea vacía con un número de 5 * n + 1 (ya que la última línea finalmente da como resultado un espacio en blanco). El espacio del patrón se ve así después del ciclo:

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

Luego sigue el formato:

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

Y finalmente, el convertidor unario a decimal permanece:

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

Básicamente agrega una cadena donde está el conocimiento de la conversión. Puede interpretarlo como: espacio: -> 1 y 0-> 1-> 2-> 3-> 4-> 5-> 6-> 7-> 8-> 9-> I0. La expresión de sustitución s/(.)I(.*\1(I?.))|;.*/\3\2/funciona de manera similar a la ordenada, reemplazando los caracteres delante de I's [ (.)I] por el carácter que está al lado del que está delante de I en la cadena de conversión [ (.*\1(I?.))] y si no queda I, se elimina la cadena adjunta [ |;.*]. La sustitución [ /\nI/s/^/ /Mg] agrega relleno si es necesario.

Gracias a Cows quack por reducir el tamaño en 26 bytes y por el algoritmo de clasificación más corto.

Triste Sed
fuente
¡Bienvenido a PPCG, y buena primera respuesta!
Kritixi Lithos
Puede usar \w(coincide con caracteres de palabras) en varios lugares para guardar algunos bytes. También :b ... tbpuede simplemente convertirse s/\B\w/X/g. Puede eliminar la línea que le sigue s/:/:,/g, modificando las sustituciones anteriores. Puede ver goo.gl/JvD7Rs (enlace TIO acortado al programa sed) para ver a qué me refiero.
Kritixi Lithos
1
Puede mejorar el algoritmo de clasificación, pista: intente agregar zyx...cbaa la entrada.
Kritixi Lithos
Brillante convertidor de unario a decimal. El suyo es al menos 30 bytes más corto que el de Consejos para jugar al golf en 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}

Pruébalo en línea!

Requiere ⎕IO←0

Camino demasiados bytes salvó gracias a Adám y vacas charlatanes !

dzaima
fuente
Para el último bit, puedes probar ⍵[⍋⍵]~' '(ordena y elimina espacios antes de pasar )
Kritixi Lithos
'X'/⍨≢∊⍕¨×
Adám
y ⍵>0×⍵
Kritixi Lithos
Su enlace TIO tiene un encabezado innecesario.
Adám
2⌷⍴≢⍉dos veces
Adám
5

05AB1E , 58 47 bytes

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

Pruébalo en línea!

-11 bytes gracias a @Emigna

Urna de pulpo mágico
fuente
Tal vez esto podría ayudar? No tengo tiempo para unirlos, pero tal vez puedan dar algo de inspiración.
Emigna
@Emigna Voy a echar un vistazo, definitivamente diferente al mío :).
Urna mágica de pulpo
@Emigna 57 bytes después de coserlo ... dado que no me esforcé demasiado por optimizar. Pruébalo en línea!
Urna mágica de pulpo
47 bytes con algo de reestructuración y optimización.
Emigna
Sus letras no se alinean con las X para ciertas 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()))

Pruébalo en línea!

Explicación

La línea 2 calcula los valores del histograma de una manera bastante sencilla, descartando ' '.

La línea 3 usa el truco de la computación ceil(x/5)como -(-x/5): redondeamos la frecuencia máxima hasta el siguiente múltiplo de 5 usando la fórmula -x/5*-5. Esto es h.

La línea 4 es un bucle que cuenta desde habajo hasta 0inclusive, imprimiendo cada fila:

  • Si y%5==2>>yimprimimos una etiqueta. Esto es cuando y∈ {1, 5, 10, 15, 20, ...}

    (Esta fórmula podría ser más corta. Solo necesitamos algo que sea 1 o Verdadero para {1, 5, 10, ...}, y 0 o Falso o incluso un entero negativo para todos los demás valores de y).

  • Justificamos a la derecha la etiqueta (o espacio vacío) en len(`-h`)espacios: ¡este es un ahorro de un byte ordenado len(`h`)+1!

  • Luego, imprimimos X's y espacios para esta fila (si y≥ 1) o las letras (si y= 0), pasando por pares clave-valor den orden ascendente.

Lynn
fuente
1
Buena creación de garrapatas con '%d-'%y*(y%5==2>>y). ¿Te importa si uso eso en mi respuesta?
dylnan
-~-(y%5*~-y)también funciona pero desafortunadamente es un byte más.
dylnan
2

Carbón , 62 bytes

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

Pruébalo en línea! El enlace es a la versión detallada del código. Explicación:

≔E²⁷⟦⟧η

Crea una lista de 27 listas.

Fθ⊞§η⌕βιι

Empuje cada carácter de entrada a la lista correspondiente a su posición en el alfabeto en minúsculas. Los caracteres que no están en minúscula son empujados a la lista 27.

≔⊟ηθ

Deseche el elemento 27 de la lista.

≦Lη

Toma las longitudes de todos los elementos de la lista.

P⭆β⎇§ηκιω

Imprima las letras minúsculas correspondientes a los elementos de la lista que no sean cero.

↑↑Φηι

Imprima los elementos de la lista que no sean cero hacia arriba. Como se trata de una matriz de enteros, cada entero se imprime como una línea (ahora vertical), cada una en una columna separada.

F÷⁺⁹⌈η⁵«

Calcule el número de marcas en el eje Y y repítelas.

≔∨×⁵ι¹ι

Calcule la posición de la siguiente marca de verificación.

J±¹±ι

Salta a la siguiente marca de verificación.

←⮌⁺ι-

Imprima la marca de verificación invertida y de atrás hacia adelante, alineándola efectivamente a la derecha.

Neil
fuente
2

Jalea , 48 bytes

¡Qué campo de minas atravesar!

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

Un programa completo que imprime el resultado (como un enlace monádico devolvería una lista que contiene caracteres y enteros [0,9])

Pruébalo en línea! O ver el conjunto de pruebas

¿Cómo?

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

Rubí , 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*''}

Pruébalo en línea!

Gracias a:

  • dylnan para -16 bytes con relleno menos estricto
  • Lynn para -2 bytes redondeando con-x/5*-5
  • Kirill L. para -2 bytes obteniendo elementos de matriz únicos con|[]
Nnnes
fuente
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;}

Pruébalo en línea!

Créditos

Olivier Grégoire
fuente
@aoemica Correcto. Lo arreglé.
Olivier Grégoire
1
No es mucho, pero puede guardar 2 bytes. --m%5==0puede ser --m%5<1, porque también tienes el &m>0cheque. Y m<=d[a]?"x":" "puede ser m>d[a]?" ":"x".
Kevin Cruijssen
@KevinCruijssen ¡2 bytes son 2 bytes! Ya no creo que haya mucho en el golf, excepto por un algoritmo diferente.
Olivier Grégoire
1
1 byte más cambiando (--m%5<1|m==1)&m>0a--m%5<1|m==1&&m>0
Kevin Cruijssen
1

Pyth, 65 bytes

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

Pruébalo aquí

Explicación

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.

fuente
1

JavaScript (Node.js) , 262 256 bytes

* Gracias a @Shaggy por reducir en 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`
`

Pruébalo en línea!

DanielIndie
fuente
Un par de ahorros rápidos que puedo detectar en mi teléfono: 1.tome la entrada como una matriz de caracteres individuales, 2.reemplace x!=" "con x>" ".
Shaggy
3.Reemplazar m=0con i=m=0y map((x,i)=>con map(x=>.
Shaggy
1

Pitón 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]

Pruébalo en línea!

Devuelve una lista de listas de caracteres que representan líneas.

  • Se guardaron algunos bytes al incluir mucho espacio en blanco adicional.
  • Tenía un innecesario map(list,yticks)allí.
  • Se modificó el relleno de espacio para guardar algunos bytes.
  • Pensé que estaba ordenando pero no estaba: +2 bytes. Pero salvé uno independientemente al mismo tiempo. y==1reemplazado por y<2.
  • -6 bytes gracias a Lynn usando en '%d-'%y*(y%5==2>>y)lugar de (`y`+'-')*(not y%5or y<2).

Ligeramente incólume:

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

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

Incluye 18 bytes para using System.Linq;

Guardado 6 bytes gracias 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;}

Pruébalo en línea!

Ian H.
fuente
Tienes un espacio j< m;que puede ser eliminado. Y int i=0,jse puede colocar como ,i=0,jdespués de las otras entradas para -4 bytes en total. using System.Linq;Sin embargo , tendrá que incluir los 18 bytes para el ..
Kevin Cruijssen
@KevinCruijssen Gracias, me los perdí. Y agregué los 18 bytes.
Ian H.
+1 de mi parte Ah, y puede guardar 2 bytes más cambiando for(;i<t;){string p=i>0&i%5<1|i==1?i+"-":"",q=p.PadLeft(o);for(j=o;j<m;){...}a[i++]=q;}a 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){...}. Pruébalo en línea.
Kevin Cruijssen
@KevinCruijssen Eso es muy inteligente, ¡gracias!
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

Pruébalo en línea!

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

Gracias a @IanM_Matrix por guardar 3 bytes.

usuario9549915
fuente
cat bpodría estar <bguardando 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);}}

La entrada se toma de la línea de comando (primer argumento). Utiliza signos de exclamación en lugar de X para reducir aún más el tamaño del código. El contador de la izquierda siempre tiene tres caracteres.

Probado con GCC y clang.

Simon
fuente
for(p=b[1];*p;p++)más probable es que puede ser for(p=b[1]-1;*++p;), main(int a,char **b)probablemente podría ser golfed a m(a,b)char**b;.
Jonathan Frech
Como a!=1será booleano, a%5&&a!=1?debería ser equivalente a a%5&a!=1?o a%5&&~-a.
Jonathan Frech
0

Excel VBA, 316 bytes

Una función de ventana inmediata anónima de VBE que toma la entrada de la celda [A1]y las salidas a la ventana inmediata de 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

Versión sin golf

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

Perl 5 -n , 198168 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

Pruébalo en línea!

Xcali
fuente
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]

Pruébalo en línea!

Puede que este no sea el enfoque más eficiente en bytes en Python, pero realmente quería resolver esto con una lambda "de una sola línea".

Emite una lista de listas de caracteres. Abusa de múltiples líneas nuevas y espacios como todos los demás. En realidad, puede reducirse aún más a 174 bytes si es aceptable incluir el resultado en otra lista, de modo que podamos transferir la [0]indexación final al pie de página.

Kirill L.
fuente
0

JavaScript (ES8), 200 bytes

Toma la entrada como una matriz de caracteres. Devuelve una cadena.

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)

Pruébalo en línea!

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
fuente