Sparkline in unicode: Difference between revisions
(Updated D entry) |
|||
Line 23: | Line 23: | ||
"Numbers please separated by space/commas: ".write; |
"Numbers please separated by space/commas: ".write; |
||
/*immutable*/ |
/*immutable*/ const numbers = readln |
||
.strip |
.strip |
||
.splitter(r"[\s,]+".regex) |
.splitter(r"[\s,]+".regex) |
||
.array /**/ |
.array /**/ |
||
.to!(real[]); |
.to!(real[]); |
||
immutable mm = numbers.reduce!(min, max); |
immutable mm = numbers.reduce!(min, max); |
||
"min: %5f; max: %5f".writefln(mm[]); |
"min: %5f; max: %5f".writefln(mm[]); |
Revision as of 18:24, 22 June 2013
You are encouraged to solve this task according to the task description, using any language you may know.
A sparkline is a graph of successive values laid out horizontally where the height of the line is proportional to the values in succession.
Use the following series of Unicode characters to create a program that takes a series of numbers separated by one or more whitespace or comma characters and generates a sparkline-type bar graph of the values on a single line of output.
The eight characters: '▁▂▃▄▅▆▇█'
(Unicode values U+2581 through U+2588).
Use your program to show sparklines for the following input, here on this page:
- 1 2 3 4 5 6 7 8 7 6 5 4 3 2 1
- 1.5, 0.5 3.5, 2.5 5.5, 4.5 7.5, 6.5
- (note the mix of separators in this second case)!
- Notes
- A space is not part of the generated sparkline.
- The sparkline may be accompanied by simple statistics of the data such as its range.
D
<lang d>void main() {
import std.stdio, std.range, std.algorithm, std.conv, std.string, std.regex;
"Numbers please separated by space/commas: ".write; /*immutable*/ const numbers = readln .strip .splitter(r"[\s,]+".regex) .array /**/ .to!(real[]); immutable mm = numbers.reduce!(min, max); "min: %5f; max: %5f".writefln(mm[]); immutable bars = iota(9601, 9609).map!(i => i.to!dchar).dtext; immutable div = (mm[1] - mm[0]) / (bars.length - 1); numbers.map!(n => bars[cast(int)((n - mm[0]) / div)]).writeln;
}</lang> The output is the same as the Python entry (but it only accepts one series of values at a time).
FALSE
<lang false>{
variables: s: sign (1 or -1) u: current number f: current number fraction length v: current number is valid t: number of numbers read x: biggest fraction y: smallest number (without fraction) z: biggest number (without fraction)
}
{function a: test if top is 0-9, without popping the value, codes 48-57 are in range} [$$47>\57>~&]a:
{function b: test if top is ',' or ' ', without popping the value} [$$',=\' =|]b:
{function c: read a number from the input, given that the first character of the input is already on the stack} [
1s:0u:0f:0v: {reset values}
$'-=[1_s:%^]? {if (it is negative) set the sign value to -1 move to next} [a;!][48-u;10*+u:1_v:^]# {while (isnumber) do number = number * 10 + decimal and set valid number and move to next} $'.=[ {if (it is a decimal) move forward and read fraction} %^ [a;!][48-u;10*+u:f;1+f:1_v:^]# {while (isnumber) do number = number * 10 + decimal and increase fraction length and set valid number and move to next} ]? $$'-=\'.=|[0v:]? {if next charachter is a '-' or a '.', set invalid}
]c:
{function d: normalize number/fraction from stack to max fraction and push that number} [
[$x;=~][1+\10*\]# {while (fraction != max) fraction + 1, value * 10} % {pop fraction}
]d:
0t: 0x: 1_v: { nothing read, so we are still valid } ^[b;!][%^]# {read away any initial separators} [$1_=~v;&][ {while input != -1 and valid input, leaving input on the stack}
c;! {read a number} t;1+t:u;s;*f;@ {increase count, push number * sign and fraction length onto the stack and bring input back up} f;x;>[f;x:]? {set fraction to biggest of current and previous biggest} [b;!][%^]# {while (isseparator) move forward}
]# v;~["error at charachter ",]? {if invalid number, tell them when} v;[ {if last number also valid, do the math}
% {pop the -1} t;2*1-q: {var q: points to next value} 0p: {var p: whether min/max have been set} [q;1+t;>][ {while q + 1 > t} q;ø {current number} q;ø {current fraction} d;! {normalize} p;[$y;\>[$y:]? $z;>[$z:]?]? {compare min/max} p;~[1_p:$y:$z:]? {if (first)) set min/max} q;1-q: {move pointer} ]#
t;q: {point q to first value} [q;0>][ {while q > 0} q;1-øy;-7*z;y;-/ {(number - minvalue) * 7 / (maxvalue - minvalue), should result in 0..7} 9601+, {print character} q;1-q: {move pointer} ]#
]?</lang> This implementation can only accept one series of numbers at a time.
- Output:
▁▂▃▄▅▆▇█▇▆▅▄▃▂▁ ▂▁▄▃▆▅█▇
Groovy
<lang groovy>def sparkline(List<Number> list) {
def (min, max) = [list.min(), list.max()] def div = (max - min) / 7 list.collect { (char)(0x2581 + (it-min) * div) }.join()
} def sparkline(String text) { sparkline(text.split(/[ ,]+/).collect { it as Double }) }</lang> Test Code <lang groovy>["1 2 3 4 5 6 7 8 7 6 5 4 3 2 1", "1.5, 0.5 3.5, 2.5 5.5, 4.5 7.5, 6.5"].each { dataset ->
println " Dataset: $dataset" println "Sparkline: ${sparkline(dataset)}"
}</lang>
- Output:
Dataset: 1 2 3 4 5 6 7 8 7 6 5 4 3 2 1 Sparkline: ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁ Dataset: 1.5, 0.5 3.5, 2.5 5.5, 4.5 7.5, 6.5 Sparkline: ▂▁▄▃▆▅█▇
Java
<lang java> public class Sparkline { String bars="▁▂▃▄▅▆▇█"; public static void main(String[] args) { Sparkline now=new Sparkline(); float[] arr={1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1}; now.display1D(arr); System.out.println(now.getSparkline(arr)); float[] arr1={1.5f, 0.5f, 3.5f, 2.5f, 5.5f, 4.5f, 7.5f, 6.5f}; now.display1D(arr1); System.out.println(now.getSparkline(arr1)); } public void display1D(float[] arr) { for(int i=0;i<arr.length;i++) System.out.print(arr[i]+" "); System.out.println(); } public String getSparkline(float[] arr) { float min=Integer.MAX_VALUE; float max=Integer.MIN_VALUE; for(int i=0;i<arr.length;i++) { if(arr[i]<min) min=arr[i]; if(arr[i]>max) max=arr[i]; } float range=max-min; int num=bars.length()-1; String line=""; for(int i=0;i<arr.length;i++) {
line+=bars.charAt((int)Math.ceil(((arr[i]-min)/range*num))); } return line; } } </lang> Output:
1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 7.0 6.0 5.0 4.0 3.0 2.0 1.0 ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁ 1.5 0.5 3.5 2.5 5.5 4.5 7.5 6.5 ▂▁▄▃▆▅█▇
Perl 6
<lang perl6>constant @bars = '▁' ... '█'; while prompt 'Numbers separated by anything: ' -> $_ {
my @numbers = map +*, .comb(/ '-'? \d+ ['.' \d+]? /); my ($mn,$mx) = @numbers.minmax.bounds; say "min: $mn.fmt('%5f'); max: $mx.fmt('%5f')"; my $div = ($mx - $mn) / (@bars - 1); say @bars[ (@numbers X- $mn) X/ $div ].join;
}</lang>
- Output:
Numbers separated by anything: 9 18 27 36 45 54 63 72 63 54 45 36 27 18 9 9 18 27 36 45 54 63 72 63 54 45 36 27 18 9 min: 9.000000; max: 72.000000 ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁ Numbers separated by anything: 1.5, 0.5 3.5, 2.5 5.5, 4.5 7.5, 6.5 1.5 0.5 3.5 2.5 5.5 4.5 7.5 6.5 min: 0.500000; max: 7.500000 ▂▁▄▃▆▅█▇ Numbers separated by anything: 3 2 1 0 -1 -2 -3 -4 -3 -2 -1 0 1 2 3 min: -4.000000; max: 3.000000 █▇▆▅▄▃▂▁▂▃▄▅▆▇█ Numbers separated by anything: ^D
Python
<lang python>import re try: raw_input except: raw_input = input
- Unicode: 9601, 9602, 9603, 9604, 9605, 9606, 9607, 9608
try: bar = u'▁▂▃▄▅▆▇█' except: bar = '▁▂▃▄▅▆▇█' barcount = len(bar) - 1 while True:
line = raw_input('Numbers please separated by space/commas: ') numbers = [float(n) for n in re.split(r'[\s,]+', line.strip())] mn, mx = min(numbers), max(numbers) extent = mx - mn sparkline = .join(bar[int( (n - mn) / extent * barcount)] for n in numbers) print('min: %5f; max: %5f' % (mn, mx)) print(sparkline)</lang>
- Output:
Numbers separated by space/commas: 1 2 3 4 5 6 7 8 7 6 5 4 3 2 1 min: 1.000000; max: 7.000000 ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁ Numbers separated by space/commas: 1.5, 0.5 3.5, 2.5 5.5, 4.5 7.5, 6.5 min: 0.500000; max: 7.500000 ▂▁▄▃▆▅█▇
Racket
<lang racket>
- lang racket (require syntax/parse)
(define bars "▁▂▃▄▅▆▇█") (define bar-count (string-length bars))
(define (sparks str)
(define ns (map string->number (string-split str #rx"[ ,]" #:repeat? #t))) (define mn (apply min ns)) (define bar-width (/ (- (apply max ns) mn) (- bar-count 1))) (apply string (for/list ([n ns]) (string-ref bars (exact-floor (/ (- n mn) bar-width))))))
(sparks "1 2 3 4 5 6 7 8 7 6 5 4 3 2 1") (sparks "1.5, 0.5 3.5, 2.5 5.5, 4.5 7.5, 6.5") </lang> Output: <lang racket> "▁▂▃▄▅▆▇█▇▆▅▄▃▂▁" "▂▁▄▃▆▅█▇" </lang>
Tcl
<lang tcl>package require Tcl 8.6
proc extractValues {series} {
return [regexp -all -inline {\d+(?:\.\d*)?|\.\d+} $series]
} proc renderValue {min max value} {
set band [expr {int(8*($value-$min)/(($max-$min)*1.01))}] return [format "%c" [expr {0x2581 + $band}]]
} proc sparkline {series} {
set values [extractValues $series] set min [tcl::mathfunc::min {*}$values] set max [tcl::mathfunc::max {*}$values] return [join [lmap v $values {renderValue $min $max $v}] ""]
}</lang> Demonstrating: <lang tcl>set data {
"1 2 3 4 5 6 7 8 7 6 5 4 3 2 1" "1.5, 0.5 3.5, 2.5 5.5, 4.5 7.5, 6.5"
} foreach series $data {
puts "Series: $series" puts "Sparkline: [sparkline $series]"
}</lang>
- Output:
Series: 1 2 3 4 5 6 7 8 7 6 5 4 3 2 1 Sparkline: ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁ Series: 1.5, 0.5 3.5, 2.5 5.5, 4.5 7.5, 6.5 Sparkline: ▂▁▄▃▆▅█▇