Typesetting multidimensional labels

In a steam-punk multidimensional world, our boss wants to affix printed index labels to each drawer in our conglomerate's multidimensional file cabinet.

The boss wants to typeset the entire label sheet as a single form, using a font bought only for this purpose, so we have to order the sorts (metal symbol pieces). Since sorts are very expensive, our order must be for the exact count of each digit-symbol.

For a given (by any means) set of lengths of dimensions ≥ 0, return (by any means) our order, which is the frequency table of digits required to typeset all the Cartesian coordinates. It must be arranged by keyboard order of appearance (i.e. 0 after 9), and may not include orders of 0 sorts, so if no sorts are to be ordered at all (because a dimension has length 0); print nothing.

• Bonus of -3 sorts if your code can handle (i.e. print nothing) 0 dimensions too.
• Final newline chars are acceptable.
• Prohibition on standard loopholes apply.
• As mentioned, sorts are expensive, this is therefore .

A kind soul may edit this challenge to include automated scoring, so include a header like:
# LanguageName, 123 sorts

Test cases

Given 11, print:

1 4
2 1
3 1
4 1
5 1
6 1
7 1
8 1
9 1
0 1


because the needed labels are 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, and 11.

Given 2 3, print:

1 5
2 5
3 2


because the needed labels are 1 1, 1 2, 1 3, 2 1, 2 2, and 2 3.

Given 2 0, print an empty line:

or nothing.

Given 1 2 3, print:

1 11
2  5
3  2


because the needed labels are 1 1 1, 1 1 2, 1 1 3, 1 2 1, 1 2 2, and 1 2 3

Given 5 5 5 5, print:

1 500
2 500
3 500
4 500
5 500


And no, I'm not going to list all 625 labels.

• I'm a little unclear about the output requirements. In the text, it says "return (by any means)", but the rest suggests that a very specific output format is required, and that it needs to be printed. Which one is it? E.g. talking about trailing newlines seems completely redundant if the output format can be anything. Nov 8, 2015 at 20:29
• @RetoKoradi the format has to look more or less as shown, but it may be in an interactive session, a file, a pop-up, STDOUT, etc. Do you have a suggestion as to how I could phrase this to make it clearer?
Nov 8, 2015 at 21:39

Mathematica, 48 bytes - 3 = 45

Grid@Tally@Flatten@IntegerDigits@Tuples@Range@#&

• That's beautiful. Nov 8, 2015 at 22:20

Dyalog APL, 10 7

The code is 10 bytes long and qualifies for the bonus.

Thanks to user46915 for 3 bytes!

,∘≢⌸∊⍕¨∊⍳⎕


Note that ⎕ (input) doesn't work on TryAPL; you can try the function form here.

            ⎕      Get input
⍳       Index vector
∊⍕¨∊        Flatten, stringify, flatten again
⌸            From the key, display the
{⍺,  }             elements concatenated with the
≢⍵              number of times they occur


I don't completely understand the ⌸ operator, but {⍺}⌸ lists the unique values taken on, and {⍵}⌸ lists their places in the argument.

This has the correct ordering because it is the order in which digits appear in the multidimensional array of labels.

• Yup, that's the solution I had in mind. This may help understanding the ⌸ Key operator.
Nov 8, 2015 at 18:42
• Doesn't APL always win at codegolf?
– vy32
Nov 9, 2015 at 3:59
• @vy32 No. APL may be the most concise general purpose language, But there will always be domain-specific languages that are better at a certain limited domain than any general purpose language. Within the specific domain of code-golfing, golfing languages like Pyth and CJam usually win. However, it is remarkable that APL, being a commercial language used in production by very large companies, comes even close. Also, for the price of being slightly more verbose, it is probably easier for humans to learn to read APL than golfing languages.
Nov 9, 2015 at 12:10
• Wait, so you mean I can make whole histogram simply with ,∘≢⌸ without any outer products with unique and such?! Dyalog sure is awesome. Also ,∘≢⌸ is shorter than {⍺,≢⍵}⌸. Nov 9, 2015 at 12:41
• @NBZ, I miss APL. Back in 1982 I wrote a graphics package in APL that drove a daisy wheel printer. It was a work of art, even though I didn't understand what I had written a month later.
– vy32
Nov 9, 2015 at 21:21

Mathematica, 111 85 bytes

Grid[Thread@{Range@10~Mod~10,DigitCount@Tuples@Range@#~Total~2}~DeleteCases~{_,‌​0}]&


Most of the work here is done by DigitCount.

• Grid[Thread@{Range@10~Mod~10,DigitCount@Tuples@Range@#~Total~2}~DeleteCases~{_,0}]& Nov 8, 2015 at 15:45

R, 110 bytes

Saved 4 thanks to Alex A. (thanks!)

U=unlist
X=table(U(strsplit(as.character(U(expand.grid(Map(seq_len,scan())))),"")))
z=Map(cat,names(X),X,"\n")

• You only use x once so you should just be able to replace the one occurrence of x with scan(). Also why assign z? Nov 8, 2015 at 23:36
• Thanks. Agree about not using x. I assigned the output of Map to a z variable otherwise Map would print its output to stdout. A better practice would be to wrap Map inside invisible() but that's a lot of characters... Nov 10, 2015 at 0:07

Ruby, 92 bytes

f,*r=$*.map{|n|[*1..n.to_i]} a=f.product(*r)*'' puts a.chars.uniq.map{|c|[c,a.count(c)]*" "}  Takes the lengths as command line arguments: $ ruby foo.rb 1 2 3
1 11
2 5
3 2


CJam, 31 bytes

Laq~{,m*}/e_:)s{_'0=A*+}$e{(S\N}%  Try it online Code is 34 bytes, and takes 3 byte bonus for working with empty input list. The input is a list in CJam format, e.g.: [1 2 3]  Explanation: La Push list containing empty list to seed Cartesian products. q~ Get and interpret input. { Loop over values in input list. , Built range from 0 to value-1. m* Form Cartesian product with the list we already have. }/ End loop over values in input list. e_ Resulting list has extra nesting. Flatten it. :) Increment all values in list, since it is 0-based, and we need 1-based. s Convert it to string, so we can operate on digits. { Block to calculate source key, needed to get 0 to the end. _ Copy the digit. '0= Compare with '0. A* Multiply comparison result by 10... + ... and add it to digit. }$    End of sort key block.
e    RLE.
{     Start of loop over RLE entries, for generating output in specified format.
(     Pop off the first value, which is the count.
S     Push a space...
\     ... and swap it with the count.
N     Push a newline.
}%    End of loop over RLE entries.


Pyth, 15 bytes

rjko%N_Ts*FSMQ8


import Data.List