15
\$\begingroup\$

Write the shortest program that generates a histogram (a graphical representation of the distribution of data).

Rules:

  • Must generate a histogram based on the character length of the words (punctuation included) input into the program. (If a word is 4 letters long, the bar representing the number 4 increases by 1)
  • Must display bar labels that correlate with the character length the bars represent.
  • All characters must be accepted.
  • If the bars must be scaled, there needs to be some way that is shown in the histogram.

Examples:

$ ./histogram This is a hole in one!
1 |#
2 |##
3 |
4 |###

$./histogram Extensive word length should not be very problematic.
1 |
2 |#
3 |#
4 |##
5 |
6 |##
7 |
8 |
9 |#
10|
11|
12|#

./histogram Very long strings of words should be just as easy to generate a histogram just as short strings of words are easy to generate a histogram for.
1 |##
2 |#######
3 |#
4 |#######
5 |###
6 |#
7 |##
8 |##
9 |##
\$\endgroup\$
5
  • 4
    \$\begingroup\$ Please write a specification rather than giving a single example which, solely by virtue of being a single example, cannot express the range of acceptable output styles, and which doesn't guarantee to cover all corner cases. It's good to have a few test cases, but it's even more important to have a good spec. \$\endgroup\$ Commented Dec 11, 2013 at 0:37
  • \$\begingroup\$ @PeterTaylor More examples given. \$\endgroup\$
    – syb0rg
    Commented Dec 11, 2013 at 2:19
  • 1
    \$\begingroup\$ 1. This is tagged graphical-output, which means that it's about drawing on the screen or creating an image file, but your examples are ascii-art. Is either acceptable? (If not then plannabus might not be happy). 2. You define punctuation as forming countable characters in a word, but you don't state which characters separate words, which characters may and may not occur in the input, and how to handle characters which may occur but which are not alphabetic, punctuation, or word separators. 3. Is it acceptable, required, or prohibited to rescale the bars to fit in a sensible size? \$\endgroup\$ Commented Dec 11, 2013 at 8:45
  • \$\begingroup\$ @PeterTaylor I didn't tag it ascii-art, because it really isn't "art". Phannabus's solution is just fine. \$\endgroup\$
    – syb0rg
    Commented Dec 11, 2013 at 13:19
  • \$\begingroup\$ @PeterTaylor I've added in some rules based on what you described. So far, all the solutions here adhere to all of the rules still. \$\endgroup\$
    – syb0rg
    Commented Dec 11, 2013 at 13:45

20 Answers 20

6
\$\begingroup\$

R, 55 47 characters

hist(a<-sapply(scan(,""),nchar),br=.5+0:max(a))

Luckily R comes with a plot function hist for histograms, here supplied with a breaks argument where the breaks are 0.5, 1.5, ... until max(input)+0.5. sapply(scan(,""),nchar) takes an input (as stdin), separates it following the spaces and count the number of characters of each element.

Examples:

hist(a<-sapply(scan(,""),nchar),br=.5+0:max(a))
1: Extensive word length should not be very problematic.
9: 
Read 8 items

enter image description here

hist(a<-sapply(scan(,""),nchar),br=.5+0:max(a))
1: Very long strings of words should be just as easy to generate a histogram just as short strings of words are easy to generate a histogram for.
28: 
Read 27 items

enter image description here

Edit:

A variation at 71 characters with an axis label at each possible value:

hist(a<-sapply(scan(,""),nchar),br=.5+0:max(a),ax=F);axis(1,at=1:max(a))

enter image description here

\$\endgroup\$
5
  • 3
    \$\begingroup\$ I love when a normally verbose language takes the lead! \$\endgroup\$
    – user8777
    Commented Dec 11, 2013 at 10:06
  • \$\begingroup\$ This doesn't comply with the specification, however... \$\endgroup\$
    – Doorknob
    Commented Dec 11, 2013 at 13:02
  • \$\begingroup\$ @Doorknob which specification doesn't it comply with? \$\endgroup\$
    – plannapus
    Commented Dec 11, 2013 at 13:06
  • \$\begingroup\$ The example testcases. \$\endgroup\$
    – Doorknob
    Commented Dec 11, 2013 at 13:07
  • 4
    \$\begingroup\$ They are examples, not specifications... \$\endgroup\$
    – plannapus
    Commented Dec 11, 2013 at 13:08
5
\$\begingroup\$

Python - 83 characters

Seems that we can take input from anywhere, so this takes input during execution, rather than from the command line, and uses Ejrb's suggestion to shorten it by 8.

s=map(len,raw_input().split())
c=0;exec'c+=1;print"%3d|"%c+"#"*s.count(c);'*max(s)

Python - 91 characters

This will fall over with quotes.

import sys;s=map(len,sys.argv[1:])
for i in range(1,max(s)+1):print"%3d|"%i+'#'*s.count(i)

Input:

> python hist.py Please write a specification rather than giving a single example which, solely by virtue of being a single example, cannot express the range of acceptable output styles, and which doesnt guarantee to cover all corner cases. Its good to have a few test cases, but its even more important to have a good spec.

Output:

  1|#####
  2|######
  3|#####
  4|##########
  5|######
  6|#############
  7|####
  8|#
  9|##
 10|#
 11|
 12|
 13|#
\$\endgroup\$
1
  • 2
    \$\begingroup\$ nice, you can shave off 4 chars by reworking your second line (no algorithm change) to use exec and string concatenation: c=0;exec'c+=1;print"%3d|"%c+"#"*s.count(c);'*max(s) \$\endgroup\$
    – ejrb
    Commented Dec 11, 2013 at 15:12
4
\$\begingroup\$

Haskell - 126 characters

p[d]=[' ',d];p n=n
h l=[1..maximum l]>>= \i->p(show i)++'|':(l>>=($"#").drop.abs.(i-))++"\n"
main=interact$h.map length.words

This takes the input from stdin, not the command line:

& head -500 /usr/share/dict/words | runhaskell 15791-Histogram.hs 
 1|##
 2|##
 3|######
 4|###############
 5|################################################
 6|###############################################################
 7|###################################################################
 8|###########################################################################
 9|#############################################################
10|##########################################################
11|#########################################################
12|#########################
13|#######
14|###
15|#####
16|###
17|#
18|
19|#
20|#
\$\endgroup\$
1
  • \$\begingroup\$ Looks good to me! +1 \$\endgroup\$
    – syb0rg
    Commented Dec 11, 2013 at 13:16
3
\$\begingroup\$

K, 35

{(1+!|/g)#`$(#:'=g:#:'" "\:x)#'"#"}

.

k){(1+!|/g)#`$(#:'=g:#:'" "\:x)#'"#"}"Very long strings of words should be just as easy to generate a histogram just as short strings of words are easy to generate a histogram for."
1| ##
2| #######
3| #
4| #######
5| ###
6| #
7| ##
8| ##
9| ##

.

A longer example

k){(1+!|/g)#`$(#:'=g:#:'" "\:x)#'"#"}"Please write a specification rather than giving a single example which, solely by virtue of being a single example, cannot express the range of acceptable output styles, and which doesnt guarantee to cover all corner cases. Its good to have a few test cases, but its even more important to have a good spec."
1 | #####
2 | ######
3 | #######
4 | ########
5 | ######
6 | ##############
7 | ###
8 | #
9 | ##
10| #
11|
12|
13| #
\$\endgroup\$
2
  • \$\begingroup\$ What happens if there are words with more than 9 letters? \$\endgroup\$
    – user8777
    Commented Dec 11, 2013 at 23:49
  • \$\begingroup\$ It works for words of any length \$\endgroup\$
    – tmartin
    Commented Dec 12, 2013 at 10:14
3
\$\begingroup\$

APL (42)

⎕ML←3⋄K,⊃⍴∘'▓'¨+⌿M∘.=K←⍳⌈/M←↑∘⍴¨I⊂⍨' '≠I←⍞

Could be shorter if I could omit lines where the value is 0.

Explanation:

  • ⎕ML←3: set the migration level to 3 (this makes (partition) more useful).
  • I⊂⍨' '≠I←⍞: read input, split on spaces
  • M←↑∘⍴¨: get the size of the first dimension of each item (word lengths), and store in M
  • K←⍳⌈/M: get the numbers from 1 to to the highest value in M, store in K
  • +⌿K∘.=M: for each value in M, see how many times it is contained in K.
  • ⊃⍴∘'▓'¨: for each value in that, get a list of that many s, and format it as a matrix.
  • K,: prepend each value in K to each row in the matrix, giving the labels.

Output:

      ⎕ML←3⋄K,⊃⍴∘'▓'¨+⌿M∘.=K←⍳⌈/M←↑∘⍴¨I⊂⍨' '≠I←⍞
This is a hole in one!
1 ▓  
2 ▓▓ 
3    
4 ▓▓▓
      ⎕ML←3⋄K,⊃⍴∘'▓'¨+⌿M∘.=K←⍳⌈/M←↑∘⍴¨I⊂⍨' '≠I←⍞
Very long strings of words should be just as easy to generate a histogram just as short strings of words are easy to generate a histogram for.
1 ▓▓     
2 ▓▓▓▓▓▓▓
3 ▓      
4 ▓▓▓▓▓▓▓
5 ▓▓▓    
6 ▓      
7 ▓▓     
8 ▓▓     
9 ▓▓     
\$\endgroup\$
0
3
\$\begingroup\$

Python 3.3 (93)

a=[len(i) for i in input().split()]
for i in range(1,max(a)+1):
 print(i,'|',"#"*a.count(i))

Output:
(the first line is the input string)

Very long strings of words should be just as easy to generate a histogram just as short strings of words are easy to generate a histogram for.
1 | ##
2 | #######
3 | #
4 | #######
5 | ###
6 | #
7 | ##
8 | ##
9 | ##

It doesn't justify numbers as Lego Stormtroopr's Python solution (which is also shorter than mine), but it's my first entry ever in a golfing contest, so I might as well leave it here I guess :)

\$\endgroup\$
6
  • \$\begingroup\$ Could you edit in an example of a generated histogram by this program? \$\endgroup\$
    – syb0rg
    Commented Dec 12, 2013 at 0:05
  • \$\begingroup\$ Yes, but I just noticed it has one problem: it doesn't justify the numbers as Lego Stormtroopr's solution, so I'm actually thinking about retiring the answer. \$\endgroup\$
    – Roberto
    Commented Dec 12, 2013 at 0:07
  • \$\begingroup\$ As long as there are labels for the represented bars, the answer is acceptable. \$\endgroup\$
    – syb0rg
    Commented Dec 12, 2013 at 0:08
  • \$\begingroup\$ Ok, done then! :) \$\endgroup\$
    – Roberto
    Commented Dec 12, 2013 at 0:12
  • \$\begingroup\$ This takes input from input, not from arguments. Is this valid @syb0rg ? \$\endgroup\$
    – user8777
    Commented Dec 12, 2013 at 22:36
3
\$\begingroup\$

Perl, 56

$d[y///c].='#'for@ARGV;printf"%2d|$d[$_]
",$_ for+1..$#d

Added @manatwork's rewrite and literal newline suggestion, thank you very much! Added @chinese_perl_goth's updates.

Usage: save as hist.pl and run perl hist.pl This is a test

Example output:

$perl ~/hist.pl This is a test of the histogram function and how it will count the number of words of specific lengths. This sentence contains a long word 'complexity'.
 1|##
 2|#####
 3|####
 4|######
 5|##
 6|#
 7|
 8|#####
 9|#
10|
11|#
\$\endgroup\$
6
  • 1
    \$\begingroup\$ Why not use printf? You could spare some characters on formatting. And some more by changing from hash to array: $d[y///c]++for@ARGV;shift@d;printf"%2d|%s\n",++$i,"#"x$_ for@d. \$\endgroup\$
    – manatwork
    Commented Dec 11, 2013 at 13:29
  • \$\begingroup\$ Can I see an example of this program at work? \$\endgroup\$
    – syb0rg
    Commented Dec 11, 2013 at 13:48
  • \$\begingroup\$ @manatwork printf didn't occur to me at all and for some reason I didn't think I could get the effect I wanted with an array, amazing! @syb0rg adding now \$\endgroup\$ Commented Dec 11, 2013 at 14:01
  • 2
    \$\begingroup\$ golfed some more, got it down to 57 bytes: $d[y///c].='#'for@ARGV;printf"%2d|$d[$_]\n",$_ for+1..$#d \$\endgroup\$ Commented Dec 12, 2013 at 21:20
  • 1
    \$\begingroup\$ We missed just the simplest trick: use a literal newline instead of \n to spare 1 more character. I mean like this: pastebin.com/496z2a0n \$\endgroup\$
    – manatwork
    Commented Dec 13, 2013 at 9:42
3
\$\begingroup\$

J, 48 47 46 45 43 characters

(;#&'#')/"1|:((],[:+/=/)1+[:i.>./)$;._1' ',

Usage:

   (;#&'#')/"1|:((],[:+/=/)1+[:i.>./)$;._1' ','Very long strings of words should be just as easy to generate a histogram just as short strings of words are easy to generate a histogram for.'
┌─┬───────┐
│1│##     │
├─┼───────┤
│2│#######│  
├─┼───────┤
│3│#      │
├─┼───────┤
│4│#######│
├─┼───────┤
│5│###    │
├─┼───────┤
│6│#      │
├─┼───────┤
│7│##     │
├─┼───────┤
│8│##     │
├─┼───────┤
│9│##     │
└─┴───────┘
\$\endgroup\$
1
  • \$\begingroup\$ Tacit, 38 [:((](;#&'#')"0[:+/=/)1+[:i.>./)#@>@;: : Try it online! \$\endgroup\$
    – Jonah
    Commented Dec 22, 2019 at 7:45
2
\$\begingroup\$

Ruby, 98 85

a=$*.group_by &:size
1.upto(a.max[0]){|i|b=a.assoc i
puts"%-2i|#{b&&?#*b[1].size}"%i}

Not golfed much. Will golf more later.

c:\a\ruby>hist This is a test for the histogram thingy. yaaaaaaaaaaaay
1 |#
2 |#
3 |##
4 |##
5 |
6 |
7 |#
8 |
9 |#
10|
11|
12|
13|
14|#
\$\endgroup\$
3
  • \$\begingroup\$ Works nicely (++voteCount). Anything I could do to word the question better? \$\endgroup\$
    – syb0rg
    Commented Dec 11, 2013 at 2:59
  • 1
    \$\begingroup\$ @syb0rg IMO the question is worded fine, the examples speak for themselves. Although your last once seems to have an error... I count 2 8-letter words (generate and generate) and 2 9-letter words (histogram, histogram) \$\endgroup\$
    – Doorknob
    Commented Dec 11, 2013 at 3:00
  • \$\begingroup\$ Cool. You could change b ?(?#*b[1].size):'' with b&&?#*b[1].size. \$\endgroup\$
    – manatwork
    Commented Dec 11, 2013 at 8:46
2
\$\begingroup\$

Powershell, 97 93

$a=@{};$args-split ' '|%{$a[$_.length]++};1..($a.Keys|sort)[-1]|%{"{0,-2} |"-f $_+"#"*$a[$_]}

Example:

PS Z:\> .\hist.ps1 This is an example of this program running
1  |
2  |###
3  |
4  |##
5  |
6  |
7  |###
\$\endgroup\$
4
  • \$\begingroup\$ Can I see an example of this program running? \$\endgroup\$
    – syb0rg
    Commented Dec 11, 2013 at 13:48
  • \$\begingroup\$ @syb0rg Sure, I've updated the answer with an example. \$\endgroup\$ Commented Dec 11, 2013 at 13:59
  • \$\begingroup\$ Looks good! +1 to you! \$\endgroup\$
    – syb0rg
    Commented Dec 11, 2013 at 14:00
  • \$\begingroup\$ Nice. You could remove extra spaces and save 6 bytes $a=@{};-split$args|%{$a[$_.length]++};1..($a.Keys|sort)[-1]|%{"{0,-2}|"-f$_+"#"*$a[$_]} \$\endgroup\$
    – mazzy
    Commented Sep 27, 2018 at 8:02
2
\$\begingroup\$

Mathematica 97

Histogram["" <> # & /@ StringCases[StringSplit[InputString[]], WordCharacter] /. 
a_String :> StringLength@a]

When I input text of the Declaration of Independence as a single string (through cut and paste, of course), the output generated was:

declaration of independence

\$\endgroup\$
2
\$\begingroup\$

Forth, 201

This was fun but my Ruby submission is more competitive. ;-)

variable w 99 cells allot w 99 cells erase : h begin
1 w next-arg ?dup while swap drop dup w @ > if dup w
! then cells + +! repeat w @ 1+ 1 ?do i . 124 emit i
cells w + @ 0 ?do 35 emit loop cr loop ; h

Sample run:

$ gforth histo.fth Forth words make for tough golfing!
1 |
2 |
3 |#
4 |#
5 |###
6 |
7 |
8 |#

Max word length is 99.

\$\endgroup\$
2
\$\begingroup\$

Ruby, 79

(1..(w=$*.group_by &:size).max[0]).map{|i|puts"%2i|#{?#*w.fetch(i,[]).size}"%i}

Example run:

$ ruby hist.rb Histograms, histograms, every where, nor any drop to drink.
 1|
 2|#
 3|##
 4|#
 5|#
 6|##
 7|
 8|
 9|
10|
11|##

Please see my Forth submission for a laugh.

\$\endgroup\$
2
\$\begingroup\$

Ruby 1.8.7, 74

A slightly different take than the other ruby solutions:

i=0;$*.map{|v|v.size}.sort.map{|v|$><<(i+1..v).map{|n|"
%2i:"%i=n}+['#']}

output:

ruby hist.rb `head -400 /usr/share/dict/words`

 1:#
 2:###
 3:######
 4:#############################
 5:#####################################################
 6:############################################################
 7:########################################################################
 8:######################################################
 9:############################################################
10:########################
11:###########################
12:######
13:#####
\$\endgroup\$
1
  • \$\begingroup\$ I didn't see this submission initially, sorry! +1 \$\endgroup\$
    – syb0rg
    Commented Jan 9, 2014 at 21:37
1
\$\begingroup\$

JavaScript (159 133)

Definitely not competitive, but so far the only JavaScript solution. Thanks to @manatwork for the tip on using String.replace.

prompt(o=[]).replace(/\S+/g,function(p){o[l=p.length]=(o[l]||'')+'#'});for(i=1;i<o.length;)console.log(i+(i>9?"|":" |")+(o[i++]||""))

Input

Code Golf is a question and answer site for programming puzzle enthusiasts and code golfers. It's built and run by you as part of the Stack Exchange network of Q&A sites. With your help, we're working together to build a library of programming puzzles and their solutions.

Output

1 |##
2 |#######
3 |#########
4 |########
5 |######
6 |###
7 |####
8 |####
9 |
10|#
11|###
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Indeed, this is not really a field where JavaScript excels. But with replace() instead of split()+for and Array instead of Object+separate length variable can be reduced with a few characters: prompt(o=[]).replace(/\S+/g,function(p){o[l=p.length]=(o[l]||"")+"#"});for(i=1;i<o.length;)console.log(i+(i>9?"|":" |")+(o[i++]||"")). (And even shorter in Harmony: prompt(o=[]).replace(/\S+/g,p=>o[l=p.length]=(o[l]||"")+"#");for(i=1;i<o.length;)console.log(i+(i>9?"|":" |")+(o[i++]||"")).) \$\endgroup\$
    – manatwork
    Commented Dec 15, 2013 at 17:03
  • \$\begingroup\$ @manatwork Nice abuse of .length there. \$\endgroup\$
    – quietmint
    Commented Dec 15, 2013 at 17:24
1
\$\begingroup\$

PHP, 162

<?php error_reporting(0);$b=0;while($argv[$b])$c[strlen($argv[++$b])]++;for($t=1;$t<=max(array_keys($c));$t++)echo $t.'|'.($c[$t]?str_repeat('#',$c[$t]):'')."\n";

Usage:

php histogram.php Very long strings of words should be just as easy to generate a histogram just as short strings of words are easy to generate a histogram for.
1|##
2|#######
3|#
4|#######
5|###
6|#
7|##
8|##
9|##
\$\endgroup\$
1
\$\begingroup\$

8th, 162 bytes

Code

a:new ( args s:len nip tuck a:@ ( 0 ) execnull rot swap n:1+ a:! ) 0 argc n:1- loop 
a:len n:1- ( dup . "|" . a:@ ( 0 ) execnull "#" swap s:* . cr ) 1 rot loop bye

Usage

$ 8th histogram.8th Nel mezzo del cammin di nostra vita mi ritrovai per una selva oscura

Output

1|
2|##
3|####
4|#
5|##
6|###
7|
8|#

Ungolfed code (SED is Stack Effect Diagram)

a:new               \ create an empty array 
( 
    args s:len      \ length of each argument
                    \ SED: array argument lengthOfArgument
    nip             \ SED: array lengthOfArgument
    tuck            \ SED: lengthOfArgument array lengthOfArgument
    a:@             \ get item array at "lengthOfArgument" position
    ( 0 ) execnull  \ if null put 0 on TOS
                    \ SED: lengthOfArgument array itemOfArray
    rot             \ SED: array itemOfArray lengthOfArgument    
    swap            \ SED: array lengthOfArgument itemOfArray
    n:1+            \ increment counter for the matching length
    a:!             \ store updated counter into array 
) 0 argc n:1- loop  \ loop through each argument
\ print histogram
a:len n:1- ( dup . "|" . a:@ ( 0 ) execnull "#" swap s:* . cr ) 1 rot loop 
bye                 \ exit program
\$\endgroup\$
1
\$\begingroup\$

Husk, 28 bytes

Ṡz+öTT' msŀSomȯ:'|R'##oḣ▲mLw

Try it online!

Husk is an ASCII art language.

\$\endgroup\$
1
\$\begingroup\$

Pure bash, 120 107 bytes

d=$*;d=${d//[ -z]/#};for a;do((b[${#a}]++));done;e=${!b[*]};for((i=0;i++<${e##* };)){ echo $i ${d:0:b[i]};}

or

d=$*
d=${d//[ -z]/#}
for a;do((b[${#a}]++));done
e=${!b[*]}
for((i=0;i++<${e##* };)){
echo $i ${d:0:b[i]}
}

or

d=$*;d=${d//[ -z]/#};for a;do((b[${#a}]++));done;e=${!b[*]}
for((i=0;i++<${e##* };)){ echo $i ${d:0:b[i]};}

Sample:

./histogram.sh Very long strings of words should be just as easy to generate a histogram just as short strings of words are easy to generate a histogram for.
1 ##
2 #######
3 #
4 #######
5 ###
6 #
7 ##
8 ##
9 ##
\$\endgroup\$
0
\$\begingroup\$

APL (Dyalog Unicode), 31 bytes (SBCS)

Anonymous tacit prefix function.

(I,'#'⍴⍤0⍨1⊥⊢∘.=I←⍳⌈/)'\S+'⎕S 1

Try it online!

'\S+'⎕S 1Search for runs of non-Space characters, returning the length of each

() apply the following tacit function to that list of lengths:

⌈/ the largest number (lit. maximum reduction)

 the indices 1…that

I← let I denote that function

⊢∘.= equality table of word lengths vertically and possible word lengths horizontally

1⊥ sum the columns (lit. evaluate in base 1, with each row representing a digit)

'#'⍴⍤0⍨ use each element to reshape the hash character, then stack the results and pad

I, prepend the result of I (i.e. all the possible lengths) as an additional column on the left

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.