13
\$\begingroup\$

This is Hole-1 from The Autumn Tournament of APL CodeGolf. I am the original author of the problem there, and thus allowed to re-post it here.


Given a list of numbers, produce a horizontal bar chart of # characters for how many numbers fit into each of ten equal-sized groups. For example, if the data ranges from 0-100, the ranges will be 0–9.9, 10–19.9, …, 90–100. (Formally, [0,10), [10,20), …, [90,100].). You may assume that there will be at least two numbers and that not all numbers will be the same.

Examples:

[1,0,0,0,0,0,0,0,0,0] gives:

#########








#        

[0,1,2,3,4,5,6,7,8,9] gives:

#
#
#
#
#
#
#
#
#
#

[0,1,2,3,4,5,6,7,8,9,10] gives:

#
#
#
#
#
#
#
#
#
##

[0,1,2,3,4,5,6,7,8,9,10,11] gives:

##
#
#
#
#
#
#
#
#
##

[0,-0.5,-1,-1.5,-2,-2.5,-3,-3.5,-4,-4.5,0.5,0,-0.5,-1,-1.5,-2,-2.5,-3,-3.5,-4,1,0.5,0,-0.5,-1,-1.5,-2,-2.5,-3,-3.5,1.5,1,0.5,0,-0.5,-1,-1.5,-2,-2.5,-3,2,1.5,1,0.5,0,-0.5,-1,-1.5,-2,-2.5,2.5,2,1.5,1,0.5,0,-0.5,-1,-1.5,-2,3,2.5,2,1.5,1,0.5,0,-0.5,-1,-1.5,3.5,3,2.5,2,1.5,1,0.5,0,-0.5,-1,4,3.5,3,2.5,2,1.5,1,0.5,0,-0.5,4.5,4,3.5,3,2.5,2,1.5,1,0.5,0] gives:

###                
#######            
###########        
###############    
#########          
###################
###############    
###########        
#######            
###                

[9014,9082,9077,9068,8866,8710,9049,8364,8867,9015,9064,9023,9024,8804,8805,8800,8744,8743,8714,9076,8593,8595,9075,9675,8968,8970,8711,8728,8834,8835,8745,8746,8869,8868,9073,9074,9042,9035,9033,9021,8854,9055,9017,9045,9038,9067,9066,8801,8802,9496,9488,9484,9492,9532,9472,9500,9508,9524,9516,9474,8739,9079,8900,8592,8594,9053,9109,9054,9059] gives:

#                        
####                     
#########                
############             
######                   
#########################


###########              
#                        

[0,8,10,13,32,12,6,7,27,9,37,39,95,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,1,2,175,46,48,49,50,51,52,53,54,55,56,57,3,165,36,163,162,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,4,5,253,183,127,193,194,195,199,200,202,203,204,205,206,207,208,210,211,212,213,217,218,219,221,254,227,236,240,242,245,123,125,168,192,196,197,198,201,209,214,216,220,223,224,225,226,228,229,230,231,232,233,234,235,237,238,239,241,91,47,92,60,61,62,45,43,247,215,63,126,42,40,124,59,44,33,243,244,246,248,34,35,30,38,180,64,249,250,251,94,252,96,182,58,191,161,41,93,31,160,167] gives:

#############             
######################    
##########################
######################### 
######################### 
#                         
########                  
################          
########################  
##########################
\$\endgroup\$
  • 3
    \$\begingroup\$ So, the final group is a tiny bit larger? Like in the first example, it would be [0.9,1] (and not [0.9,1))? \$\endgroup\$ – Felix Palmen Oct 17 '17 at 8:37
  • \$\begingroup\$ @FelixPalmen Kind of. It is only larger by an infinitely small amount. \$\endgroup\$ – Adám Oct 17 '17 at 8:48
  • \$\begingroup\$ Ok, important thing to know was that it's indeed the last group that should include both endpoints, thanks \$\endgroup\$ – Felix Palmen Oct 17 '17 at 8:51
  • \$\begingroup\$ @FelixPalmen Ah, I see that that wasn't entirely clear in the OP. I'll edit it in. \$\endgroup\$ – Adám Oct 17 '17 at 9:00
  • 1
    \$\begingroup\$ @Adám Should it be reverse instead? The top row is [0,1) containing only 0 while the bottom row is [9,10] contains both 9 and 10. \$\endgroup\$ – user202729 Oct 18 '17 at 10:56

17 Answers 17

4
\$\begingroup\$

Python 2, 96 bytes

l=input()
m=min(l)
w=max(l)-m
for i in range(10):print"#"*sum(w*i<=(x-m)*10<w*-~i+i/9for x in l)

Try it online!

\$\endgroup\$
4
\$\begingroup\$

Python 2, 107 95 bytes

l=input();m=min(l);s=(max(l)-m)/10.;c=0
exec'print"#"*sum(m<=v-c*s<m+s+c/9for v in l);c+=1;'*10

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ Alternative 107-byter without exec. \$\endgroup\$ – Mr. Xcoder Oct 17 '17 at 10:01
  • \$\begingroup\$ I rolled back your edit with my suggestion, because *.1 does not work instead of /10. for the very last test case. TBH I don't know why it does not work. \$\endgroup\$ – Mr. Xcoder Oct 17 '17 at 11:04
4
\$\begingroup\$

R, 77 81 bytes

+4 bytes to fix some test cases

for(i in hist(x<-scan(),seq(min(x),max(x),,11),r=F)$c)cat(rep('#',i),'\n',sep='')

Try it online!

Link is to a version of the code that takes comma-separated input; this version takes space-separated.

Reads from stdin, prints to stdout.

R is a statistical programming language that does its best to give high-quality results, which is sometimes frustrating:

hist bins the inputs into a histogram with breaks as its second argument. Normally, one would expect that you could specify that the number of breaks to be 10. Indeed, this is the case:

breaks

one of:

  • a vector giving the breakpoints between histogram cells,
  • a function to compute the vector of breakpoints,
  • a single number giving the number of cells for the histogram,
  • a character string naming an algorithm to compute the number of cells (see ‘Details’),
  • a function to compute the number of cells.

(emphasis added).

The next sentence, however, says:

In the last three cases the number is a suggestion only; as the breakpoints will be set to pretty values, the number is limited to 1e6 (with a warning if it was larger).

So I looked at the documentation of pretty and it just doesn't work for our situation, because it picks break points thusly:

Compute a sequence of about n+1 equally spaced ‘round’ values which cover the range of the values in x. The values are chosen so that they are 1, 2 or 5 times a power of 10.

Which simply won't do.

So the seq(min(x),max(x),,11) specifies 11 equally-spaced points as the breaks, hist(x,breaks,r=F)$c gives the counts, r=F ensures that the bins are right-open intervals, and the for loop takes care of the rest.

\$\endgroup\$
3
\$\begingroup\$

C (gcc), 241 bytes

#define P(x)for(;x--;putchar('#'));puts("");
double a[999],u,l,x;i,j,n[9];main(k){for(;scanf("%lf",&x)>0;u=u>x?u:x,l=l<x?l:x,a[i++]=x);for(;j<i;++j)for(k=0;k<9;)if(a[j]<l+(++k)*(u-l)/10){n[k-1]++;break;}for(k=0;k<9;++k){i-=n[k];P(n[k])}P(i)}

Try it online!

\$\endgroup\$
  • \$\begingroup\$ I think you can make k as a global, (+1byte) however it is initialized to 0, thus save 3 bytes from k=0. \$\endgroup\$ – user202729 Oct 17 '17 at 10:34
  • \$\begingroup\$ Also you can switch double to float and lf to f, save another 2 bytes. (at least that works on TIO) \$\endgroup\$ – user202729 Oct 17 '17 at 10:58
  • \$\begingroup\$ @user202729 for your first comment: no, this initialization is needed inside the outer loop multiple times. float might work, I didn't use it because it is not the "standard" floating-point type in C and reduces precision, so not sure this is allowed ... \$\endgroup\$ – Felix Palmen Oct 17 '17 at 11:06
3
\$\begingroup\$

Mathematica, 152 bytes

(Do[Print[""<>Table["#",Length@Select[s=#,Min@s+(t=#2-#&@@MinMax@s/10)(i-1)<=#<Min@s+t*i&]]],{i,9}];Print[""<>Table["#",Length@Select[s,Max@s-t<=#&]]])&


Try it online!

\$\endgroup\$
  • \$\begingroup\$ How should it work? TIO only have text output. (reply to the part "Dennis will fix it") \$\endgroup\$ – user202729 Oct 17 '17 at 9:06
  • 1
    \$\begingroup\$ @user202729 Do you really believe that I'm not aware of this? or... \$\endgroup\$ – J42161217 Oct 17 '17 at 9:32
  • 2
    \$\begingroup\$ Not to offend you, but you mention Range[0,9] while I'm talking about Range[0,10] for no reason. But it actually fail for Range[0,10]: TIO. \$\endgroup\$ – user202729 Oct 17 '17 at 9:35
  • 4
    \$\begingroup\$ You used <= on both ends, which is correct on the last segment but not the 9 other ones. \$\endgroup\$ – user202729 Oct 17 '17 at 9:43
  • 3
    \$\begingroup\$ @user202729 hey!this one helped me as much as your previous info that Range[0,n]={0,..n}. +1 for great advice. anyways the code works fine now \$\endgroup\$ – J42161217 Oct 17 '17 at 13:20
3
\$\begingroup\$

JavaScript (ES6), 99 bytes

Edit 2 bytes save thx @JustinMariner

A function returning an array of strings

l=>l.map(v=>o[i=(v-n)/(Math.max(...l)-n)*10|0,i>9?9:i]+='#',o=Array(10).fill``,n=Math.min(...l))&&o

Less golfed

list => {
   var max = Math.max(...list),
       min = Math.min(...list),
       output = Array(10).fill(''),
       index;

   list.forEach( value => (
      index = (value - min) / (max - min) * 10 | 0,
      output [index > 9 ? 9 : index] += '#'
   ) )
   return output
}

Test

var F=
l=>l.map(v=>o[i=(v-n)/(Math.max(...l)-n)*10|0,i>9?9:i]+='#',o=Array(10).fill``,n=Math.min(...l))&&o

var test=[
[1,0,0,0,0,0,0,0,0,0],
[0,1,2,3,4,5,6,7,8,9],
[0,-0.5,-1,-1.5,-2,-2.5,-3,-3.5,-4,-4.5,0.5,0,-0.5,-1,-1.5,-2,-2.5,-3,-3.5,-4,1,0.5,0,-0.5,-1,-1.5,-2,-2.5,-3,-3.5,1.5,1,0.5,0,-0.5,-1,-1.5,-2,-2.5,-3,2,1.5,1,0.5,0,-0.5,-1,-1.5,-2,-2.5,2.5,2,1.5,1,0.5,0,-0.5,-1,-1.5,-2,3,2.5,2,1.5,1,0.5,0,-0.5,-1,-1.5,3.5,3,2.5,2,1.5,1,0.5,0,-0.5,-1,4,3.5,3,2.5,2,1.5,1,0.5,0,-0.5,4.5,4,3.5,3,2.5,2,1.5,1,0.5,0],
[0,8,10,13,32,12,6,7,27,9,37,39,95,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,1,2,175,46,48,49,50,51,52,53,54,55,56,57,3,165,36,163,162,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,4,5,253,183,127,193,194,195,199,200,202,203,204,205,206,207,208,210,211,212,213,217,218,219,221,254,227,236,240,242,245,123,125,168,192,196,197,198,201,209,214,216,220,223,224,225,226,228,229,230,231,232,233,234,235,237,238,239,241,91,47,92,60,61,62,45,43,247,215,63,126,42,40,124,59,44,33,243,244,246,248,34,35,30,38,180,64,249,250,251,94,252,96,182,58,191,161,41,93,31,160,167],
[9014,9082,9077,9068,8866,8710,9049,8364,8867,9015,9064,9023,9024,8804,8805,8800,8744,8743,8714,9076,8593,8595,9075,9675,8968,8970,8711,8728,8834,8835,8745,8746,8869,8868,9073,9074,9042,9035,9033,9021,8854,9055,9017,9045,9038,9067,9066,8801,8802,9496,9488,9484,9492,9532,9472,9500,9508,9524,9516,9474,8739,9079,8900,8592,8594,9053,9109,9054,9059]];

output=x=>O.textContent+=x+'\n\n'

test.forEach(t=>output(t+'\n'+F(t).join`\n`))
<pre id=O></pre>

\$\endgroup\$
  • \$\begingroup\$ You should be able to save a couple bytes by moving the assignment for i into the array brackets followed by a comma, allowing you to remove the parentheses around the body of the map function: Try it online! \$\endgroup\$ – Justin Mariner Oct 17 '17 at 16:53
  • \$\begingroup\$ @JustinMariner right, thx \$\endgroup\$ – edc65 Oct 17 '17 at 18:35
  • \$\begingroup\$ You can actually save one more byte if you get rid of i and use Math.min again, with an alias: Try it online! \$\endgroup\$ – Justin Mariner Oct 22 '17 at 19:30
2
\$\begingroup\$

Python 2, 126 121 bytes

def f(a):
 m=min(a);r=range(10);A=[sum(x>=m+i*(max(a)-m)/10.for x in a)for i in r]+[0]
 for i in r:print'#'*(A[i]-A[i+1])

Try it online!

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

Jelly, 21 bytes

A monadic link returns a list of strings.

_Ṃµ÷Ṁ×⁵Ḟµ<⁵+ċЀ⁵R¤”#ẋ

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Although return a list of lines is permitted, the displayed result is not separated in any way. I don't know whether that is valid. \$\endgroup\$ – user202729 Oct 17 '17 at 10:01
  • \$\begingroup\$ It is allowed, since that's how Jelly treats lists of string. You can add ÇŒṘ or ÇY in your footer in order to visualize the result. Also instead of full program, you can say that your submission is a monadic link, that returns rather than printing, making it automatically valid. \$\endgroup\$ – Mr. Xcoder Oct 17 '17 at 10:03
2
\$\begingroup\$

Pyth,  32  31 bytes

*R\#_M.++msmgk+JhSQ*dc-eSQJTQTZ

Try it here! or Verify all the test cases. (with pretty-print using j)

How this works

This is a full program that takes input from STDIN. This is for the 32-byte version. I'll update it soon.

*R\#_M.++msmgk+hSQ*dc-eSQhSQTQTZ  ~ Full program.

         m                    T   ~ Map over [0, 10) with var d.
           m                 Q    ~ Map over the input with var k.
            g                     ~ Is higher than or equal to?
             k                    ~ The current element of the input, k.
              +hSQ*dc-eSQhSQT     ~ We'll break this down into pieces:
               hSQ                  ~ The lowest element of the input list.
              +                     ~ Plus:
                  *dc-eSQhSQT       ~ We'll break this down into more pieces:
                  *                   ~ Multiplication.
                   d                  ~ The current element of [0, 10), d.
                    c       T         ~ Float division by 10 of:
                     -eSQhSQ          ~ The difference between the maximum and minium
                                        of the input list.
          s                       ~ Sum. Count the number of truthy results.
        +                      Z  ~ Append a 0.
      .+                          ~ Get the deltas.
    _M                            ~ Gets -delta for each delta in the list above.
  \#                              ~ The literal character "#".
*R                                ~ Vectorized multiplication. Optionally, you can
                                    use j to join by newlines (as the link does).
                                  ~ Output implicitly.
\$\endgroup\$
2
\$\begingroup\$

Charcoal, 31 bytes

≔I⪪S,θEχ×#ΣEθ⁼ι⌊⟦⁹⌊×χ∕⁻λ⌊θ⁻⌈θ⌊θ

Try it online! Link is to verbose version of code. Input of variable-length lists seems to a little awkward in Charcoal, so I've had to wrap the list in an array containing a string. Explanation:

   S                            Input string
  ⪪ ,                           Split on commas
 I                              Cast elements to integer
≔    θ                          Assign to variable q
      Eχ                        Map from 0 to 9
           Eθ                   Map over the list
                      ⁻λ⌊θ      Subtract the minimum from the current
                          ⁻⌈θ⌊θ Subtract the minimum from the maximum
                     ∕          Divide
                   ×χ           Multiply by 10
                  ⌊             Floor
               ⌊⟦⁹              Take minimum with 9
             ⁼ι                 Compare to outer map variable
          Σ                     Take the sum
        ×#                      Repeat # that many times
                                Implicitly print on separate lines
\$\endgroup\$
2
\$\begingroup\$

Fortran 2003, 263 bytes

I wrote it on GNU gfortran 5.4.0, and compiled without any additional flags.

It reads from STDIN, one value at a time, and prints to STDOUT.

Here it goes:

program h;real,allocatable::a(:);character f*9;allocate(a(0));do;read(*,*,end=8)r;a=[a,r];enddo;9 format("(",i0,"(""#""))")
8 a=(a-minval(a))+epsilon(1.);a=ceiling(10*a/maxval(a));do i=1,10;j=count(a==i);if(j==0)print*;if(j==0)cycle;write(f,9)j;
print f;enddo;end

Ungolfed explanation: (I don't know if "golfed" can be applied to fortran but either way :P)

program h
real,allocatable::a(:)       ! Create an allocatable array so we can reallocate dynamically
character f*9                ! A character array to format the output
allocate(a(0))               ! Allocate "a" empty at first
do
  read(*,*,end=8)r           ! Read from STDIN. If EOF, goes to 8, otherwise
  a=[a,r]                    ! Appends to "a"
enddo
9 format("(",i0,"(""#""))")  ! A format label
8 a=(a-minval(a))+epsilon(1.)! (8) Normalizes a (adds epsilon to avoid zero-indexing)
a=ceiling(10*a/maxval(a))    ! Normalizing and multiplying by the number of bins
do i=1,10                    ! Looping on all the bins
  j=count(a==i)              ! Counting the number of occurrences
  if(j==0)print*             ! If none, prints empty line
  if(j==0)cycle              ! And skips the rest of the loop
  write(f,9)j                ! Otherwise writes the count(j) to the print label
  print f                    ! And prints to STDOUT
enddo
end

Fun fact: I made a similar code just yesterday to test my implementation of a Weibull random number generator, so it only needed a little adaptation :)

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

Perl 5, 85 + 1 (-a) = 86 bytes

@F=sort{$a<=>$b}@F;map$r[($_-$F[0])/($F[-1]-$F[0])*10].='#',@F;$r[9].=pop@r;say for@r

Try it online!

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

Perl 5, 84 + 19 (-MList::Util=min,max) bytes

$s=-($m=min@_=@ARGV)+max@_;$a[($_-$m)*10/$s]++for@_;$a[9]+=pop@a;print"#"x$_,$/for@a

Try It Online

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

Perl 5, 102 bytes

$l=(@n=sort{$a<=>$b}<>)[-1]-($f=$n[0]);$m=$f+$l*$_/10,say'#'x(@n-(@n=grep$_>=$m,@n))for 1..9;say'#'x@n

Try it online.

Ungolfed:

my @n = sort { $a <=> $b } <>;
my $f = $n[0];
my $l = $n[-1] - $n[0];
for (1 .. 9) {
    my $m = $f + $l * ($_ / 10);
    my $c = scalar @n;
    @n = grep { $_ >= $m } @n;
    say('#' x ($c - scalar @n));
}
say('#' x scalar @n);
\$\endgroup\$
1
\$\begingroup\$

Java (OpenJDK 8), 246 221 209 207 206 163 162 161 157 bytes

l->{String x="";double b=l[0],m=b,q,i;for(double d:l){b=d<b?d:b;m=d>m?d:m;}for(i=(m-b)/10,q=b;q<m;q+=i,x+="\n")for(double d:l)x+=d>=q&d<q+i?"#":"";return x;}

Try it online!

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

q/kdb+, 52 bytes

Solution:

{sum[t=/:bin[m+.1*(t:(!)10)*max[x]-m:min x;x]]#'"#"}

Try it online! (Note the TIO link is a 44 byte K (oK) port of this solution as there is no TIO for q/kdb+).

Examples:

q){sum[t=/:bin[m+.1*(t:(!)10)*max[x]-m:min x;x]]#'"#"}1 0 0 0 0 0 0 0 0 0f
"#########"
""
""
""
""
""
""
""
""
,"#

q){sum[t=/:bin[m+.1*(t:(!)10)*max[x]-m:min x;x]]#'"#"}9014 9082 9077 9068 8866 8710 9049 8364 8867 9015 9064 9023 9024 8804 8805 8800 8744 8743 8714 9076 8593 8595 9075 9675 8968 8970 8711 8728 8834 8835 8745 8746 8869 8868 9073 9074 9042 9035 9033 9021 8854 9055 9017 9045 9038 9067 9066 8801 8802 9496 9488 9484 9492 9532 9472 9500 9508 9524 9516 9474 8739 9079 8900 8592 8594 9053 9109 9054 9059f
,"#"
"####"
"#########"
"############"
"######"
"#########################"
""
""
"###########"
,"#"

Explanation:

Most of the code is used creating the buckets that bin buckets the input into.

{sum[t=/:bin[m+.1*(t:til 10)*max[x]-m:min x;x]]#'"#"} / ungolfed solution
{                                                   } / lambda function with implicit x as parameter
                                               #'"#"  / take (#) each-both "#", 1 2 3#'"#" => "#","##","###"
 sum[                                         ]       / sum up everything inside the brackets
         bin[                              ;x]        / binary search each x in list (first parameter)
                                    m:min x           / store minimum of list x in variable m
                             max[x]-                  / subtract from the maximum of list x
                  (t:til 10)*                         / range 0..9 vectorised multiplication against max delta of list
               .1*                                    / multiply by 0.1 (aka divide by 10)
             m+                                       / minimum of list vectorised addition against list
     t=/:                                             / match each-right against range 0..9 (buckets)
\$\endgroup\$
0
\$\begingroup\$

Jelly, 19 bytes

_Ṃµ÷Ṁ×⁵Ḟ«9ċЀ⁵Ḷ¤”#ẋ

Try it online!

This is based upon my APL answer for the original problem, which I will post after that competition is over.

How? (I'm not good at explaining things)

_Ṃµ÷Ṁ×⁵Ḟ«9ċЀ⁵Ḷ¤”#ẋ
_Ṃ                  = subtract the minimum
  µ                 = Sort of like a reverse-order compose
   ÷Ṁ               = divide by the max
     ×⁵             = Multiply by 10
       Ḟ            = Take the floor
        «9          = x => min(x,9)
          ċЀ⁵Ḷ¤    = count occurrences of [0,...,9]
                ”#ẋ = create the list
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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