Read numbers in the base of the largest digit and write it using underscores

This isn't as much a "challenge" as "a unique problem that there are no built-in functions to solve." Basically, you need to do this:

• Read some lines of numbers from stdin. These lines may contain trailing or preceding whitespace, and there may be empty lines. No lines will contain "just whitespace" other than a newline. Each non-empty line will have exactly one number. This:

 123

456\t


(where \t is a tab) is considered valid input.

• Read the numbers in the input in base N+1, where N is the largest digit in any of the lines. In this case, the largest digit is 6, so the numbers would be read in base 7, resulting in 6610 and 23710.

• Find the sum of the numbers. The sum of 6610 and 23710 is 30310.

• Convert the sum back to base N+1 again. We'd convert 30310 to base 7, which would be 6127.

• For each digit, print that many underscores, followed by a space. The last digit should instead be followed by a newline or a space and a newline. In our example, that would be ______ _ __\n or ______ _ __ \n, where \n is the newline character.

Here's an example in Python:

import sys

def convert_to_base(n, b):
'Convert n to base b'
res = []
while n:
res.append(n % b)
n /= b
return res[::-1]

lines = map(str.strip, filter(None, list(sys.stdin)))
# find the largest digit, and add 1 to it to make our base
base = max(map(max, (map(int, line) for line in lines)))+1
# read the lines in the base and sum them
result = sum(int(line, base) for line in lines)
# print the result in the original base using underscores, separated by spaces
for number in convert_to_base(result, base):
print '_'*number,
# print a newline
print


This is code golf: the shortest program wins!

• Can you add <sub>7</sub> and <sub>10</sub> to your instructions? - nevermind - i just did that. Jun 4 '15 at 2:10
• @NotthatCharles What do you mean? Jun 4 '15 at 2:12
• I was unclear about which base numbers were in. I edited your question to make them explicit (pending review) Jun 4 '15 at 2:14
• @NotthatCharles Ah! Thanks! Jun 4 '15 at 2:16

Pyth, 26

JscR).zjd*R\_jsiRKhseSsJJK


Demonstration.

JscR).z
.z                       Take the input as a list of lines.
cR)                         Remove all whitespace from each line.
s                            Combine the lines.
J                             Save the result to J.
J is now the list of the string forms of the numbers.
jd*R\_jsiRKhseSsJJK
sJ      Combine J into one string.
eS        Find the maximum of that string.
s          Convert it to an integer.
K            Save to K. K is the base.
iRK      J     Convert the strings in J to base K.
j           K    Convert the result back to base K, as a list of ints.
*R\_                 Map each int in that list to that many underscores.
jd                     Join on spaces and print.

• Your Pyth answers always manage to surprise me! Jun 4 '15 at 2:12

CJam, 28 27 bytes

q_$W=~)_@N%::~fb:+\b'_f*S*N  UPDATE - 1 byte saved thanks to Martin Try it online here Pyth, 24 bytes Just found this question via Twitter. Notice that quite large parts of the program are similar to isaacg's solution (like base-conversion and the printing part), but the main algorithm is completely different. .V0#jd*R\_jsiRbcjd.z)b.q  Try it online: Demonstration My solution is based on this answer, I gave to a similar question two months ago. Explanation: .V0 for b in [0, 1, 2, ...): #__________________.q try-catch block. If ___ is successful, exit the program (.q), otherwise do nothing cjd.z) read all input (.z), join lines by spaces (jd) and split (c)) this gives a list of numbers (but still in string format) iRb convert each number from base b s sum, add all numbers up j b convert to base b *R\_ multiply each digit with "_" jd join with spaces implicit print  The infinite loop .V0 combined with the try-catch #___.q basically finds the first number b >= 0, with which the conversion iRb doesn't throw an error. And this happens, when b is equal to the largest digit + 1. PHP, 188 182 function f($s){$b=max(str_split($s))+1;foreach(preg_split('/\s/',$s)as$x)$m+=base_convert($x,$b,10);foreach(str_split(base_convert($m,10,$b))as$d)echo' ',str_repeat('_',$d);echo'  ';} prints a leading blank instead of a trailing one. if not accepted, add +1. breakdown: function f($s)
{
$b=max(str_split($s))+1;           // find base
foreach(preg_split('/\s/',$s)as$x) // extract all words and loop
$m+=base_convert($x,$b,10); // convert, sum up foreach(str_split(base_convert($m,10,$b))as$d) // convert back, split into array, loop
echo' ',str_repeat('_',\$d);    // print underscores
echo'
';                                     // append newline
}


I wonder if there is a golfier approach to this ...