Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Given an input of a list of integers representing dates, output an ASCII art timeline like the following:

<----------------------------->
  A     B  C           D    E

The above timeline is the output for input [1990, 1996, 1999, 2011, 2016]. Note several things about the timeline:

  • The first line of output is a less than sign (<), a number of dashes equal to dateOfLastEvent - dateOfFirstEvent + 3 (because one must be added to include the last date, and then two more for padding), and then a greater than sign (>).

  • In the second line of output, each event is placed at position dateOfEvent - dateOfFirstEvent + 2 (assuming zero-indexing). Hence, the first event is placed at position 2, two characters to the right of the <, and the last event is similarly two characters to the left of the >.

  • Each event is represented by a letter. Event 1 is A, event 2 is B, etc. There will never be more than 26 events. You may use lowercase letters if you would like.

  • There is no trailing whitespace. The only extra whitespace allowed is a trailing newline at the end of the program.

Furthermore,

  • The events are not necessarily given in order. Dates are still labelled according to their position in the array, though. For example, an input of [2, 3, 1, 5, 4] must output

    <------->
      CABED
    
  • You may be given one or more events as input. For example, an input of [12345] must output

    <--->
      A
    
  • You may assume that the input will never contain duplicate dates.

Input may be given as either an array/list of integers/strings or a single string separated by any non-numerical character. The allowable range of dates that will be provided as input is 1 ≤ x ≤ 32767.

Since this is , the shortest code in bytes will win.

Test cases:

32767 32715 32716 32750 32730 32729 32722 32766 32740 32762
<------------------------------------------------------->
  BC     G      FE         I         D           J   HA
2015 2014
<---->
  BA
1990 1996 1999 2011 2016
<----------------------------->
  A     B  C           D    E
2 3 1 5 4
<------->
  CABED
12345
<--->
  A
share|improve this question

10 Answers 10

Pyth, 37 36 35 34 bytes

:*dlp++\<*\-+3-eJSQhJ">
"mhh-dhJQG

Explanation: (for this the newline will be replaced by \n for simplicity)

:*dlp++\<*\-+3-eJSQhJ">\n"mhh-dhJQG

                                    - autoassign Q = eval(input())
                                    - G = "abcdefghijklmnopqrstuvwxyz"

    p++\<*\-+3-eJSQhJ">\n"          -    print out the first line

            +3-eJSQhJ               -        Get the number of dashes
                 SQ                 -            sorted(Q)
                J                   -           autoassign J = ^
               e                    -          ^[-1]
              -                     -         ^-V
                   hJ               -          J[0]
            +3                      -        ^+3

         *\-                        -       ^*"-"
      +\<                           -      "<"+^
     +               ">\n"          -     ^+"-->\n"
    p                               -    print(^)

 *dl                                -  work out the number of spaces to print
   l                                -   len(^)
 *d                                 -  ^*" "
:                                 G - For i in V: ^[i] = G[i]
                          mhh-dhJQ  -  Work out the positions of the characters
                          m      Q  -  [V for d in Q]
                               hJ   -     J[0]
                             -d     -    d-^
                           hh       -   ^+2

Try it here!

share|improve this answer

PowerShell, 120 108 bytes

param($a)$n,$m=($a|sort)[0,-1];"<$('-'*($b=$m-$n+3))>";$o=,' '*$b;$i=97;$a|%{$o[$_-$n+2]=[char]$i++};-join$o

Takes input $a then sets $n and $m to the minimal and maximal values, respectively. We output the timeline with the next section, by executing a code block $(...) inside the string to generate the appropriate number of - characters. We then generate an array of the same length containing only spaces, and set our output character to $i.

Then, we loop through the input $a with |%{...}. Each loop we set the appropriate $o value. Finally, we -join $o together to form a string. Since that is left on the pipeline, output is implicit.

Edited to remove the .TrimEnd() command, as the last character of $o is always guaranteed to be a letter.

Example

PS C:\Tools\Scripts\golfing> .\draw-a-timeline.ps1 2015,2014,2000
<------------------>
  c             ba
share|improve this answer

C - 294 287 220 191 184 178 174 bytes

After staring out with a somewhat insane code I at least have gotten it down a bit ...

Note: First loop has the requirement that the execution of the binary gives 0 as result from atoi() on argv[0]. If not, this would result in the binary (name) being included as an event. Examples that invalidates:

$ 42/program 1 2 3
# 42/program gives 42 from argv[0], fail.

$ 1program 3 2 9
# 1program gives 1 from argv[0], fail.

$ 842 3 2 9
# 842 gives 842 from argv[0], fail.

Not sure if this is a valid requirement.

char y[32769];n,m;main(i,a)char**a;{for(;n=atoi(a[--i]);y[n>m?m=n:n]=64+i);for(;!y[++i];);printf("<");for(n=i;i<=m;i+=printf("-"))!y[i]?y[i]=' ':0;printf("-->\n  %s\n",y+n);}

Run:

./cabed 32767 32715 32716 32750 32730 32729 32722 32766 32740 32762
<------------------------------------------------------->
  BC     G      FE         I         D           J   HA

./cabed 2 1 3 5 4
<------->
  BACED

./cabed 2016
<--->
  A

./cabed 130 155 133 142 139 149 148 121 124 127 136
<------------------------------------->
  H  I  J  A  C  K  E  D     GF     B

Ungolfed:

#include <stdio.h>
#include <stdlib.h>

char y[32769]; /* Zero filled as it is in global scope. */
int n, m;

int main(i, a) 
    char**a; 
{
    /* Loop argv and set y[argv[i] as int] = Letter, (Event name).
     * Set m = Max value and thus last data element in y. */
    for ( ; n = atoi(a[--i]); y[n > m ? m = n : n] = 64 + i)
        ;

    /* i = 0. Find first element in y that has a value. (Min value.) */
    for (; !y[++i]; )
        ;

    printf("<");

    /* Save min value / y-index where data starts to n.
     * Print dashes until y-index = max 
     * Build rest of event string by filling in spaces where no letters.*/
    for (n = i; i <= m; i += printf("-"))
        !y[i] ? y[i] = ' ' : 0;

    printf("-->\n  %s\n", y + n);

    return 0;
}
share|improve this answer

MATL, 40 41 bytes

0lY2in:)GtX<-I+(t~32w(ctn45lbX"60hP62hcw

Try it online!

0          % array initiallized to 0
lY2        % string 'ABC...Z'
in:)       % input array. Take as many letters as its length
GtX<-I+    % push input again. Duplicate, subtract minimum and add 3
(          % assign selected letter to those positions. Rest entries are 0
t~32w(     % replace 0 by 32 (space)
c          % convert to char
tn45lbX"   % duplicate, get length. Generate array of 45 ('-') repeated that many times
60hP62h    % prepend 60 ('<'), postpend 62 ('>')
c          % convert to char
w          % swap. Implicit display
share|improve this answer

Ruby, 83 characters

->a{n,m=a.minmax
s=' '*(d=m-n+3)
l=?@
a.map{|i|s[i-n+2]=l.next!}
puts ?<+?-*d+?>,s}

Sample run:

irb(main):001:0> ->a{n,m=a.minmax;s=' '*(d=m-n+3);l=?@;a.map{|i|s[i-n+2]=l.next!};puts ?<+?-*d+?>,s}[[32767,32715,32716,32750,32730,32729,32722,32766,32740,32762]]
<------------------------------------------------------->
  BC     G      FE         I         D           J   HA
share|improve this answer

JavaScript (ES6), 124

l=>(l.map(v=>r[v-Math.min(...l)]=(++i).toString(36),r=[],i=9),`<-${'-'.repeat(r.length)}->
  `+[...r].map(x=>x||' ').join``)

TEST

F=
l=>(l.map(v=>r[v-Math.min(...l)]=(++i).toString(36),r=[],i=9),`<-${'-'.repeat(r.length)}->
  `+[...r].map(x=>x||' ').join``)

console.log=x=>O.textContent+=x+'\n'

test= [[32767,32715,32716,32750,32730,32729,32722,32766,32740,32762],
[2015,2014],[1990,1996,1999,2011,2016],[2,3,1,5,4],[12345]]

test.forEach(x=>console.log(x+'\n'+F(x)+'\n'))
<pre id=O></pre>

share|improve this answer

PHP, 129 126 125 121 117 bytes

Uses ISO 8859-1 encoding.

$l=min([$h=max($z=$argv)]+$z)-3;echo str_pad(~Ã,$h-$l,~Ò).~ÒÁõ;for(;$l<$h;)echo chr((array_search(++$l,$z)-1^32)+65);

Run like this (-d added for aesthetics only):

php -d error_reporting=30709 -r '$l=min([$h=max($z=$argv)]+$z)-3;echo str_pad(~Ã,$h-$l,~Ò).~ÒÁõ;for(;$l<$h;)echo chr((array_search(++$l,$z)-1^32)+65); echo"\n";' 1990 1996 1999 2016 2011

Ungolfed version:

// Get the highest input value.
$h = max($z = $argv);

// Get the lowest value, setting the first argument (script name) to the highest
// so it is ignored.
$l = min([$h] + $z);

// Output the first line.
echo "<".str_repeat("-",$h - $l + 3).">\n  ";

// Iterate from $l to $h.
for(;$l <= $h;)
    // Find the index of the current iteration. If found, convert the numeric
    // index to a char. If not found, print a space.
    echo ($s = array_search($l++, $z)) ? chr($s+64) : " ";
  • Saved 3 bytes by printing leading spaces from the loop and changing <= to <.
  • Saved a byte by using str_pad instead of str_repeat.
  • Saved 4 bytes by using bitwise logic to convert 0 (false) to 32, and everything above 0 to 97 onwards. Then convert that number to char.
  • Saved 4 bytes by using negated extended ASCII to yield <, -, > and newline
share|improve this answer

Perl, 109 bytes

includes +1 for -p

$l=A;s/\d+/$h{$&}=$l++/ge;($a,$z)=(sort keys%h)[0,-1];$o.=$h{$_}//$"for$a..$z;$_='<'.'-'x($z-$a+3).">$/  $o"

Expects input on stdin: space separated numbers. Example:

$ echo 2016 2012 2013 | perl -p file.pl
<------->
  BC  A

Somewhat readable:

$l=A;                                   # Intialize $l with the letter A
s/\d+/$h{$&}=$l++/ge;                   # construct %h hash with number->letter
($a,$z) = (sort keys %h)[0,-1];         # grab min/max numbers
$o .= $h{$_} // $" for $a..$z;          # construct 2nd line: letter or space
$_= '<' . '-' x ($z-$a+3) . ">$/  $o"   # construct 1st line, merge both lines to $_ output
share|improve this answer

Python 2, 173 172 182 bytes

since Python is missing yet, here is my first post:

import sys
d=dict([(int(v),chr(65+i))for(i,v)in enumerate(sys.argv[1:])])
k=sorted(d.keys())
f=k[0]
s=k[-1]-f+3
o=list(" "*s)
for i in k:o[i-f+2]=d[i]
print "<"+"-"*s+">\n"+"".join(o)

the original looks following:

import sys

dates = dict([(int(v), chr(65+i)) for (i,v) in enumerate(sys.argv[1:])])
keys = sorted(dates.keys())
first = keys[0]
out_size = keys[-1] - first + 3
out = list(" " * out_size)
for date in keys: out[date - first + 2] = dates[date]
print "<" + "-" * out_size + ">\n" + "".join(out)
share|improve this answer
1  
You need import sys in your golfed version. – Mego Feb 22 at 9:17
    
ok, I will, but I have never seen any imports in the golfed versions, so I just left it out – BloodyD Feb 23 at 9:34

Groovy, 106 99 characters

{n=it.min()
o=[l="A"]
it.each{o[it-n]=l++}
"<${"-"*(it.max()-n+3)}>\n  "+o.collect{it?:" "}.join()}

Sample run:

groovy:000> print(({n=it.min();o=[l="A"];it.each{o[it-n]=l++};"<${"-"*(it.max()-n+3)}>\n  "+o.collect{it?:" "}.join()})([32767,32715,32716,32750,32730,32729,32722,32766,32740,32762]))
<------------------------------------------------------->
  BC     G      FE         I         D           J   HA
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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