Гістограма алфавіту


33

З огляду на вхідне речення, що складається з одного або декількох слів [a-z]+та нульових чи більше пробілів , виведіть ASCII-графічну гістограму (гістограму) розподілу літер вхідного речення.

Гістограма повинна бути викладена горизонтально, тобто буквеною лінією по нижній частині в алфавітному порядку зліва направо, з міткою осі Y 1-та кожні 5 одиниць. Вісь Y має бути найменшим кратним з п’яти, що має принаймні висоту, як найвища смуга, і повинна бути вирівняна правою. Вісь X позначена вхідними літерами без проміжків між ними. Наприклад, вхід a bb ddповинен мати мітку, abdа не ab d, пропускаючи c. Самі смуги можуть бути виконані будь-яким послідовним символом ASCII - я буду використовувати Xтут у своїх прикладах.

test example

5-

   X
   X   X
1-XXXXXXXX
  aelmpstx

Оскільки є три e, два tта один із almsx.

Більше прикладів:

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

I / O та правила

  • Введення даних може бути здійснено у будь-якому розумному форматі та будь-яким зручним способом . Це також означає, що ви можете взяти вхід у великих літерах, якщо це має більше сенсу для вашого коду.
  • Провідні / остаточні рядки чи інші пробіли необов’язкові, за умови, що символи розташовуються належним чином.
  • Прийнятна або повна програма, або функція. Якщо функція, ви можете повернути вихід, а не надрукувати його.
  • Вихід може бути на консолі, повернутий у вигляді списку рядків, повернутий як окремий рядок тощо.
  • Стандартні лазівки заборонені.
  • Це тому діють усі звичайні правила гольфу, і найкоротший код (у байтах) виграє.

3
Я думаю, що це буде швидше графік, а не гістограма, оскільки це категоричні, а не числові дані, але я здебільшого педантичний.
Джузеппе

чи гарантовано вхід не порожній?
dzaima

2
Це просто кулон, але це не гістограма , це гістограма . Все-таки приємний виклик, хоча!
caird coinheringaahing

4
Туфтіанським підходом було б зробити смужки з зображених символів, а не мати окремий рядок міток.
dmckee

2
Символ гістограми повинен бути послідовним, але в різних випадках або в кожному випадку?
Адам

Відповіді:



7

R , 239 230 байт

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

Спробуйте в Інтернеті!

table робить важкий підйом тут, уніфікуючи персонажів, сортуючи їх та повертаючи їх кількість.

Все інше - це лише те, щоб офсети були правильними для друку, що є "справжнім" твором виклику мистецтва.

Дякуємо @dylnan, що вказав на помилку.

Завдяки @rturnbull за scanпідхід, скинувши 2 байти.



@rturnbull мені вдалося вибити ще кілька байтів після цього, дякую!
Джузеппе

6

gnu sed -r, 516 490 278 249 + 1 байт

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

Спробуйте в Інтернеті!


Я впевнений, що це можна вдосконалити , але поки що це має бути добре, враховуючи, що це зроблено в sed, де у вас немає арифметики чи сортування. Тому я збрехав, це було недостатньо добре, тому я вдосконалив (переписав) його ще на 212 байт, з підказкою щодо алгоритму сортування від крауд-корів , що дало мені ідею зробити унарне десяткове перетворення також коротшим.
Опис внутрішніх виробок:

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

Цей цикл працює, зменшуючи розмір кожної групи символів на одну, додаючи відсортовану оригінальну лінію та збільшуючи одинарні лічильники після двокрапки, що залишилася від сортування. Він зациклюється, поки не буде досягнуто порожнього рядка з числом 5 * n + 1 (оскільки останній рядок в кінцевому рахунку призводить до пробілу). Простір шаблону виглядає приблизно так після циклу:

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

Тоді слід форматування:

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

І нарешті, залишається одинарний до десяткового перетворювача:

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

Він в основному додає рядок, де є знання перетворення. Ви можете інтерпретувати це як: пробіл: -> 1 і 0-> 1-> 2-> 3-> 4-> 5-> 6-> 7-> 8-> 9-> I0. Вираз заміни s/(.)I(.*\1(I?.))|;.*/\3\2/працює аналогічно сортування, замінюючи символи перед I [[ (.)I] символом, який знаходиться поруч із символом, розташованим перед лицьовою стороною I у рядку перетворення [ (.*\1(I?.))], і якщо не залишилося я, він видаляється доданий рядок [ |;.*]. Заміна [ /\nI/s/^/ /Mg] при необхідності додає набивання.

Завдяки кряканню корів за зменшення розміру на 26 байт та за коротший алгоритм сортування.


Ласкаво просимо до PPCG, і приємна перша відповідь!
Крітіксі Літос

Ви можете використовувати \w(відповідає слово символів) у ряді місць, щоб зберегти кілька байтів. Також :b ... tbможе просто стати s/\B\w/X/g. Ви можете видалити рядок, що слідує за нею, s/:/:,/gзмінивши попередні заміни. Ви можете подивитися goo.gl/JvD7Rs (скорочено TIO посилання на програму sed), щоб побачити, що я маю на увазі.
Крітіксі Літос

1
Можна вдосконалити алгоритм сортування, підказка: спробуйте додати zyx...cbaдо вводу.
Крітіксі Літос

Блискучий одинарний до десяткового перетворювача! Ваш на щонайменше на 30 байт коротший, ніж у
Радах

5

Діялог APL , 109 97 96 95 93 88 байт

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

Спробуйте в Інтернеті!

Вимагає ⎕IO←0

Шлях надто багато байт збережені завдяки Адаму і Корові кри !


Останній шматочок можна спробувати ⍵[⍋⍵]~' '(сортувати та видаляти пробіли перед тим, як проїхати )
Kritixi Lithos

'X'/⍨≢∊⍕¨×
Адам

та ⍵>0×⍵
Kritixi Lithos

У вашому посиланні TIO є непотрібний заголовок.
Адам

2⌷⍴≢⍉двічі
Adám

5

05AB1E , 58 47 байт

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

Спробуйте в Інтернеті!

-11 байт завдяки @Emigna


Може, це може допомогти? Не встигайте зв’язати їх разом, але, можливо, вони можуть дати певне натхнення.
Емінья

@Emigna Я буду дивитись, безумовно, інший, ніж мій :).
Чарівний Восьминіг Урна

@Emigna 57 байт після того, як я прошив його ... враховуючи, що я не дуже намагався оптимізувати. Спробуйте в Інтернеті!
Чарівний восьминіг Урна

47 байт з деякою перебудовою та оптимізацією.
Емінья

Ваші листи не відповідають рядкам X для певних даних. tio.run/##AVUAqv8wNWFiMWX//…
mbomb007

3

Python 2 , 192 байти

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()))

Спробуйте в Інтернеті!

Пояснення

Рядок 2 обчислює значення гістограми досить просто, відкидаючи ' '.

У рядку 3 використовується фокус обчислення ceil(x/5)як -(-x/5): округлюємо максимальну частоту до наступного кратного 5 за допомогою формули -x/5*-5. Це єh .

Рядок 4 - це цикл, що рахується від hнижнього до 0включно, друкуючи кожен рядок:

  • Якщо y%5==2>>yми друкуємо етикетку. Це коли y∈ {1, 5, 10, 15, 20,…}

    (Ця формула може бути коротшою. Нам просто потрібно щось, що є 1 або Істинним для {1, 5, 10, ...} і 0 або Невірно або навіть від'ємне ціле число для всіх інших значень y.)

  • Ми правильно виправдовуємо мітку (або порожній простір) на len(`-h`)пробіли: це акуратне однобайтне заощадження len(`h`)+1!

  • Потім ми друкуємо або Xs та пробіли для цього рядка (якщо y≥ 1), або літери (якщо y= 0), пробігаючи пари ключових значень уd у порядку зростання.


1
Гарне створення галочок за допомогою '%d-'%y*(y%5==2>>y). Ви не заперечуєте, якщо я використовую це у своїй відповіді?
ділнан

-~-(y%5*~-y)також працює, але, на жаль, це на один байт довше.
ділнан

2

Вугілля деревне , 62 байти

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

Спробуйте в Інтернеті! Посилання на багатослівну версію коду. Пояснення:

≔E²⁷⟦⟧η

Створіть список із 27 списків.

Fθ⊞§η⌕βιι

Натисніть кожен символ введення до списку, який відповідає його положенню в рядковому алфавіті. Персонажі, що знаходяться з малих літер, пересуваються до 27-го списку.

≔⊟ηθ

Відмовтеся від 27-го елемента списку.

≦Lη

Візьміть довжини всіх елементів списку.

P⭆β⎇§ηκιω

Роздрукуйте малі літери, що відповідають ненульовим елементам списку.

↑↑Φηι

Друкуйте ненульові елементи списку вгору. Оскільки це масив цілих чисел, кожне ціле число друкується як (тепер вертикальний) рядок, кожне в окремому стовпці.

F÷⁺⁹⌈η⁵«

Обчисліть кількість галочок на осі Y та петлю над ними.

≔∨×⁵ι¹ι

Обчисліть позицію наступного галочки.

J±¹±ι

Перейти до наступної галочки.

←⮌⁺ι-

Роздрукуйте галочку, перевернуту назад і вперед, ефективно вирівнюючи її вправо.


2

Желе , 48 байт

Яке мінне поле перейти!

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

Повна програма, що друкує результат (як монадичне посилання повертає список із символами та цілими числами від [0,9])

Спробуйте в Інтернеті! Або подивіться набір тестів

Як?

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


2

Рубі , 250 248 234 188 173 157 153 байт

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

Спробуйте в Інтернеті!

Завдяки:

  • дилнан на -16 байт з менш суворим набиванням
  • Лінн на -2 байти шляхом округлення до-x/5*-5
  • Кирилл Л. на -2 байти, отримуючи унікальні елементи масиву с|[]

2

Java (JDK 10) , 296 байт

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;}

Спробуйте в Інтернеті!

Кредити


@aoemica Correct. I fixed it.
Olivier Grégoire

1
It's not much, but you can save 2 bytes. --m%5==0 can be --m%5<1, because you also have the &m>0 check. And m<=d[a]?"x":" " can be m>d[a]?" ":"x".
Kevin Cruijssen

@KevinCruijssen 2 bytes are 2 bytes! I don't think there is much to golf anymore, except for a different algorithm.
Olivier Grégoire

1
1 more byte by changing (--m%5<1|m==1)&m>0 to --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

Try it here

Explanation

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.

1

JavaScript (Node.js), 262 256 bytes

*Thanks to @Shaggy for reducing by 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`
`

Try it online!


Couple of quick savings I can spot on my phone: 1. Take input as an array of individual characters, 2. Replace x!=" " with x>" ".
Shaggy

3. Replace m=0 with i=m=0 and map((x,i)=> with 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]

Try it online!

Returns a list of lists of characters representing lines.

  • Saved some bytes by including a lot of extra whitespace.
  • Had an unnecessary map(list,yticks) in there.
  • Changed space padding to save some bytes.
  • I thought I was sorting but I was not: +2 bytes. But I saved one independently at the same time. y==1 replaced by y<2.
  • -6 bytes thanks to Lynn by using '%d-'%y*(y%5==2>>y) instead of (`y`+'-')*(not y%5or y<2).

Slightly ungolfed:

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.

1

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

Includes 18 bytes for using System.Linq;

Saved 6 bytes thanks to @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;}

Try it online!


You have a space at j< m; that can be removed. And int i=0,j can be placed as ,i=0,j after the other ints for -4 bytes in total. You'll have to including the 18 bytes for the using System.Linq; however..
Kevin Cruijssen

@KevinCruijssen Thanks, I missed these. And I added the 18 bytes.
Ian H.

+1 from me. Oh, and you can save 2 more bytes by changing 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;} to 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){...}. Try it online.
Kevin Cruijssen

@KevinCruijssen Thats really clever, thanks!
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

Try it online!

Annotated:

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

Thanks to @IanM_Matrix for saving 3 bytes.


cat b could be <b saving 3 characters
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);}}

Input is taken from the command line (first argument). Uses exclamation marks instead of X's to further reduce code size. Counter on the left is always three characters long.

Tested with GCC and clang.


for(p=b[1];*p;p++) can most likely be for(p=b[1]-1;*++p;), main(int a,char **b) could probably be golfed to m(a,b)char**b;.
Jonathan Frech

Since a!=1 will be boolean, a%5&&a!=1? should be equivalent to a%5&a!=1? or a%5&&~-a.
Jonathan Frech

0

Excel VBA, 316 bytes

An Anonymous VBE immediate window function that takes input from cell [A1] and outputs to the VBE immediate window.

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

Ungolfed Version

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

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

Try it online!


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]

Try it online!

This may not be the most byte-efficient approach in Python, but I really wanted to solve this with a "true one-liner" lambda.

Outputs a list of character lists. Abuses multiple leading newlines and spaces just like everybody else. It may actually be further reduced to 174 bytes if it is acceptable to wrap the result in another list, so that we could transfer the final [0] indexing to the footer.


0

JavaScript (ES8), 200 bytes

Takes input as an array of characters. Returns a 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)

Try it online!

Commented

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.