58
\$\begingroup\$

You may remember in first or second grade using expanded form to learn about place value of numbers. It's easier to explain with an example, so consider the number 123. In expanded form it is represented as 100 + 20 + 3, which helps a young mind visualize place value. It is reminiscent of how you say it: one hundred (plus) twenty (plus) three.

We can extend this past the units place with decimals: 2.718 => 2 + 0.7 + 0.01 + 0.008

Your challenge is to write a program or function that takes a positive floating point number or zero (assume it is as large or precise as your language can handle; it will not be in scientific notation) or string and prints/returns it in expanded form as explained above.

You need neither spaces between the +'s nor the zero before the decimal point, so the example above could be 2+.7+.01+.008. Values that would be equal to zero must be omitted (101.01 => 100 + 1 + 0.01) unless the input is zero (see below).

Values should not have more than one leading zero before the decimal point or any trailing zeroes after it (no-no's: 0060, 0000.2, 30., 30.000, .0400). The input will conform to this too.

Since first-graders have short attention spans, your code will have to be as short as possible.

Test cases

0 => 0
6 => 6
0.99 => 0.9 + 0.09
24601 => 20000 + 4000 + 600 + 1
6.283 => 6 + 0.2 + 0.08 + 0.003
9000000.0000009 => 9000000 + 0.0000009
\$\endgroup\$
13
  • 22
    \$\begingroup\$ +1 for "Since first-graders have short attention spans, your code will have to be as short as possible." \$\endgroup\$
    – Downgoat
    Commented Jan 9, 2016 at 1:42
  • 2
    \$\begingroup\$ @Doᴡɴɢᴏᴀᴛ glad to see the meme is still running. \$\endgroup\$
    – cat
    Commented Jan 9, 2016 at 4:52
  • 4
    \$\begingroup\$ It would have be funny to do it in the same way we (french) count, to see people strugle with the case of 97(4*20+10+7) ^^ \$\endgroup\$
    – Katenkyo
    Commented Jan 18, 2016 at 12:14
  • 2
    \$\begingroup\$ @jimmy23013 Yes, as long as it works in theory. \$\endgroup\$ Commented Jan 18, 2016 at 14:07
  • 1
    \$\begingroup\$ @Ogaday I don't know, it's only some edge cases. Maybe NBZ way would be better, but still, don't if it would really be interesting \$\endgroup\$
    – Katenkyo
    Commented Jan 22, 2016 at 13:12

27 Answers 27

6
\$\begingroup\$

CJam, 33 26 bytes

r_ee\'0fe<f{\~t~}{},'+*0e|

This won't work with the Java interpreter; it print floats differently. Try it with the CJam interpreter.

The last test case prints 9000000+9e-7, which has been ruled valid by @NinjaBearMonkey.

Thanks to @jimmy23013 for golfing off 7 bytes!

How it works

r_                           Read a token from STDIN and push a copy.
  ee                         Enumerate its characters, i.e., push the array of all
                             [index character] pairs.
    \                        Swap the original input on top of the stack.
     '0fe<                   Perform vectorized minimum with the character '0'.
                             This replaces all digits with '0', but leaves '.'
                             untouched, since `.' < '0'.
          f{    }            For each [index character] pair, push the pair and the
                             string of zeroes and (possibly) a dot; then:
            \                    Swap the pair on top of the stack.
             ~                   Dump index and character on the stack.
              t                  Replace the string's element at that index with
                                 that character.
               ~                 Evaluate the resulting string.
                 {},         Filter the array to remove zeroes.
                    '+*      Join, using '+' as separator.
                       0e|   If the result is empty, replace it with 0.
\$\endgroup\$
2
  • \$\begingroup\$ Based on the same idea: r_ee\'0fe<f{\~t~}{},'+*0e|. \$\endgroup\$
    – jimmy23013
    Commented Jan 21, 2016 at 19:41
  • \$\begingroup\$ @jimmy23013 Wow, that is short! Thank you! \$\endgroup\$
    – Dennis
    Commented Jan 21, 2016 at 20:11
5
\$\begingroup\$

JavaScript (ES7), 102 bytes

n=>+n&&[...n.replace(/^\.0*|\./,"")].map(f=d=>10**p--*d,p=Math.floor(Math.log10(n))).filter(f).join`+`

Explanation

Requires the number to be input as a string without leading zeroes (unless the number is 0 of course).

Note: Because of floating-point weirdness some numbers (like .3) come out wrong, but theoretically this works for any number.

n=>                             // n = input number as string
  +n&&                          // return 0 if n = 0
  [...n.replace(/^\.0*|\./,"")] // remove leading zeroes after the decimal place
  .map(f=d=>                    // for each digit d in n
      10**p--*d,                // raise the digit to the correct power of 10
    p=Math.floor(Math.log10(n)) // p = power of 10 for the first digit, floor needs to be
  )                             //     used instead of |0 due to negative powers of 10 :(
  .filter(f)                    // remove zeroes, the map function is reused
  .join`+`                      // return the output numbers joined with +

Test

Test uses Math.pow instead of ** for browser compatibility.

var solution = n=>+n&&[...n.replace(/^\.0*|\./,"")].map(f=d=>Math.pow(10,p--)*d,p=Math.floor(Math.log10(n))).filter(f).join`+`
<input type="number" oninput="result.textContent=solution(this.value)">
<pre id="result"></pre>

\$\endgroup\$
8
  • \$\begingroup\$ Math.floor => 0|...? \$\endgroup\$ Commented Jan 10, 2016 at 22:54
  • \$\begingroup\$ @ETHproductions If the input number is less than 1 it would break because Math.log10(n) would return a negative number and |0 rounds towards zero instead of flooring. \$\endgroup\$
    – user81655
    Commented Jan 10, 2016 at 23:22
  • \$\begingroup\$ Can you use 0|Math.log10(n),p-=p<0 instead of Math.floor(Math.log10(n))? \$\endgroup\$ Commented Jan 19, 2016 at 9:57
  • 1
    \$\begingroup\$ @DomHastings Almost. It fails for n<1 because the 0| will make p equal 0 for both 0.1 and -0.1. The shortest way I can think of is p=Math.log10(n),p=p-(p<0)|0 which is the same length as using Math.floor. :( \$\endgroup\$
    – user81655
    Commented Jan 19, 2016 at 22:32
  • \$\begingroup\$ @DomHastings Still wouldn't work for n=0.1 anyway. \$\endgroup\$
    – Neil
    Commented Jan 20, 2016 at 20:50
5
\$\begingroup\$

Retina, 86 77 75 bytes

Byte count assumes that the source is encoded as ISO 8859-1.

S_`.(?<=(\.\d+))|(?=(\d*)).
Tm`d`0`\..+\B|(?<=^\d).+
¶([.0]+¶)*
+
^0.|\+0$

The trailing linefeed is significant.

Try it online.

Explanation

S_`.(?<=(\.\d+))|(?=(\d*)).

We start by turning the input into a linefeed separate list of components, although only the leading (or trailing) digit is correct. This is done by abusing a split stage. Instead of splitting the input we match all of it, so the remaining segments are all empty. We remove those empty segments with the _ option. The catch is that split stages also return the values of all capturing groups. So we use a lookahead at each match to capture the correct part of the string: first we try to find a . left of the match. If that's the case, we capture everything from the . up to and including the digit we're currently matching. Otherwise, we must be in the integer part of the input, so we capture all the numbers after the match (including the match). We must also get rid of the decimal point itself, so the second capture is optional. If there are no \d to be capture, this will simply remove the match from the input.

Tm`d`0`\..+\B|(?<!=\d).+

Now we use a transliteration stage to turn all but the leading/trailing digits into zeroes. We either match a component that's less than 1 with \..+\B where the \B ensures that we stop the match one digit before the end, or we match an integer part with (?<=^\d).+ where the lookbehind ensures that we start one digit into the number. The transliteration stage will then replace any digits (d) with zeroes inside the matches.

¶([.0]+¶)*
+

Now the actual output format should use + not linefeeds as separators. The matches a linefeed to do that substitution. While we're at it, we also remove lines that contain only 0s and .s.

^0.|\+0$

The previous stage does not remove a leading or trailing 0 (because those do not have a linefeed before and after them), so we remove those explicitly.

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

Python 2, 216 210 196 175 bytes

Here is some slightly golfed code that I will golf further when I get time. It uses string analysis.

i=input().split(".")
I=i[0]
e=enumerate
o=[(k+len(I[j+1::])*"0") for j,k in e(I) if k!="0"] 
try:o+=["."+l*"0"+m for l,m in e(i[1]) if m!="0"]
except:0
print "+".join(o or"0")

Explanation

So, the input is seperated into a integer and decimal part. Then, there is a for loop list comprehension. On the integer part, the length of the string after a character in the decimal is multiplied by "0" to get that many zeros at the end if that character.

For the decimal part, the index of the current character is the number of zeros before it and so that part is simple.

The try and except is used to determine whether it has a decimal part or not (using an error).

The final result is joined with plus signs.

Try it here!

\$\endgroup\$
2
  • 2
    \$\begingroup\$ I think o if o else ["0"] can be o or["0"]. \$\endgroup\$
    – lirtosiast
    Commented Jan 19, 2016 at 3:06
  • \$\begingroup\$ You have a trailing space on line four which adds to your byte count. On line four you only need one colon. You can delete the spaces in the following snippets: o=[(...)] for,e(I) if,e(i[1]) if,print "+", and the outer parenthesis in o=[(...) as well, actually. Finally, you can take the final conditional out of the join function like this: print"+".join(o)or"0" because join will return an empty list if o is empty so the conditional will evaluate the same way which saves you one byte. \$\endgroup\$
    – Ogaday
    Commented Jan 21, 2016 at 10:26
3
\$\begingroup\$

Pyth, 30 bytes

L.xvbytb|j\+fT.eyXXzjkUT\0kbzz

Test suite

The basic solution here is to replace all of the digits in the input with 0, then insert each digit at the proper location, eval, filter out the zeros, and join on pluses. Unfortunately, Pyth's eval function doesn't accept leading zeros currently. I will be working to fix this.

To get past this problem, I added a helper function, y, which recursively retries the eval until no error is thrown, removing the first digit every time. Note that this function will loop infinitely on invalid input.

Also, a special case was needed for the input 0.

All in all, I think the code's pretty good, but the language facilities could be better. Who wants errors?

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

Python 3, 138

This is loosely based on TanMath/Ogaday's approach of reading the number as a string and parsing it out that way. I have to use star assignment on i so that it correctly handles integers.

j,*i=input().split(".")
e=enumerate
z="0"
print("+".join([(x+len(j[y+1:])*z)for y,x in e(j)if x>z]+["."+o*z+p for o,p in e(i)if p>z]or z))
\$\endgroup\$
3
\$\begingroup\$

Python, 141 132 128 bytes

This one is still relatively readable. Convert to string and handle the >1 digits separately from the <1 digits. We also have a special case for zero. I could remove two more spaces below, but I like keeping it pretty.

The downside is that it will breakdown for floats with more than 9 decimal places.

x=str(int(a*1e9))
l=len(x)-10
z="0"
print"+".join([(j+z*(l-i))if l>=i
 else"."+z*(i-l-1)+j
 for i,j in enumerate(x)if j!=z]or z)

Below is the original. First edit was to shorten the zero special case, second edit was to remove the 0 before the decimal, third was to remove some extra parenthesis and spaces.

x=str(int(a*1e9))
l=len(x)-10
z="0"
print "+".join([(j+z*(l-i)) if l>=i
 else ("0."+z*(i-l-1)+j)
 for i,j in enumerate(x) if j!=z]) if a else z

Explanation:

x=str(int(a*1e9)) # Convert into a string with nine decimals
l=len(x)-10
z="0"
print "+".join([
 (j+z*(l-i)) if l>=i       # Print numbers greater than 1
 else ("0."+z*(i-l-1)+j)   # Print less than one
 for i,j in enumerate(x) if j!=z
]) if a else z             # Special case zero
\$\endgroup\$
2
  • \$\begingroup\$ You don't need to include every revision of your code; if we want to see your golfing progress we can look at the revision history. By the way, welcome to PPCG! \$\endgroup\$
    – lirtosiast
    Commented Jan 25, 2016 at 20:32
  • 1
    \$\begingroup\$ Just discovered it... I'm going to have to try not to spend too much time on this site! \$\endgroup\$
    – speedplane
    Commented Jan 25, 2016 at 22:11
2
\$\begingroup\$

Mathematica, 81 bytes

Inactive@Plus@@(10.^Range[#2-1,#2-Length@#,-1]#/.{0.->Nothing[]})&@@RealDigits@#&

Test case:

%[101.01]
(* 100. + 1. + 0.01 *)
\$\endgroup\$
1
  • 3
    \$\begingroup\$ I don't think having the decimal point over the integer parts is allowed. \$\endgroup\$ Commented Jan 18, 2016 at 11:33
2
\$\begingroup\$

CJam, 44 bytes

r:TdLT'.-{'0f+IaaI~g*+}fI:dATW%'.##m]f/'+*e&

Try it here.

It fails the last test case, and outputs the following:

9000000+9e-7

But let's say it's too precise that CJam cannot handle it.

Explanation

r:Td
LT'.-         e# Remove the period if any.
{             e# For each character I:
  '0f+        e# Append 0 to each previous string.
  IaaI~g*+    e# Append I as a string if I isn't '0.
}fI
:d            e# Convert each string to float.
ATW%'.##      e# 10 to the kth power where k is the position of the period from the end.
m]            e# Round up, so it becomes 1 if no periods are found.
f/            e# Divide each float by this number.
'+*e&         e# Format and the 0 special case.
\$\endgroup\$
2
+100
\$\begingroup\$

Python 3, 187 180 173 154 bytes

Managed to golf a good 19 bytes off thanks to @Thomas Kwa's suggestions above about result or['0'], plus rearranging some algebra (154 bytes):

def f(n):
 *m,=n;o='0'
 try:p=m.index('.');m.pop(p)
 except:p=len(m)
 return'+'.join([['.'+o*(i-p)+d,d+o*(p-i-1)][p>i]for i,d in enumerate(m)if d!=o])or o

My best attempt so far (173 bytes). Based upon new approach, see bottom of post:

def f(n):
 *m,=n;o='0'
 try:p=m.index('.');m.pop(p)
 except:p=len(m)
 return(o,'+'.join([['.'+o*(-1*(p-i))+d,d+o*(p-i-1)][p-i>0]for i,d in enumerate(m)if d!=o]))[eval(n)!=0]

golfed my original down to 180 bytes:

def f(n):x=n.split('.');a,b=(x+[''],x)[len(x)-1];e=enumerate;return('0',"+".join([d+'0'*i for i,d in e(a[::-1])if d!='0'][::-1]+['.'+'0'*i+d for i,d in e(b)if d!='0']))[eval(n)!=0]

I learnt a new language feature today doing this! Conditionals via boolean indexing. I may have slightly overdone it.

I tried abstracting out the comprehensions, but I couldn't make it any shorter (196 bytes):

e=lambda s:[d+'0'*(len(s)-i-1) for i,d in enumerate(s) if eval(d)]
def f(n):x=n.split('.');a,b=(x+[''],x)[len(x)-1];return['0',"+".join(e(a)+['.'+d[::-1]for d in e(b[::-1])][::-1])][bool(eval(n))]

(Reversing sequences is expensive!)

Whilst mine is shorter for now, I think TanMath can golf his down to match mine: Using e=enumerate, replacing pass with 0, and using '0' in place of ['0'] in the return statement should save 4+3+2=9 bytes! Taking it down to 187. I'm sure another few bytes can be shaved off somewhere...

edit New approach (156 bytes). However, it can only deal with precision up to 6dp similar to @jimmy23013's CJam entry, so it fails the final test. I couldn't coerce it to print more 0s, maybe someone else can. Instead I used it as the basis of my best attempt yet, see top (Also, this approach prints the 0 before the decimal place, but that seems valid as well.). Took the try:... except:... approach from TanMath:

def f(n):
 *m,=n
 try:p=m.index('.');m.pop(p)
 except:p=len(m)
 return('0','+'.join([str(eval(d)*10**(p-i-1))for i,d in enumerate(m)if d!='0']))[eval(n)!=0] 
\$\endgroup\$
2
  • \$\begingroup\$ If you are trying to give golfing help to me, please include them as comments to my answer, not in your answer. I do not always see your answers, so by writing a comment, I will get a notification and definitely see it. \$\endgroup\$
    – TanMath
    Commented Jan 20, 2016 at 21:25
  • 2
    \$\begingroup\$ Hi @TanMath. I would, but I don't have enough rep to comment on other people's posts yet. Once I get a few more upboats I'll make sure to leave feedback in comments. \$\endgroup\$
    – Ogaday
    Commented Jan 20, 2016 at 23:33
2
\$\begingroup\$

pure bash, 210

o= a=${1%.*} b=${1#$a};while [ "$a" ];do c=${a:1};((${a%$c}>0))&&o+=${a%$c}${c//?/0}+;a=$c;done;[ "$b" ]&&{ b=${b#.} a=;while [ "$b" ];do c=${b:0:1};((c>0))&&o+=.$a$c+;b=${b:1};a+=0;done;};o=${o%+};echo ${o:-0}

or

o= a=${1%.*} b=${1#$a};while [ "$a" ];do c=${a:1};((${a%$c}>0))&&
o+=${a%$c}${c//?/0}+;a=$c;done;[ "$b" ]&&{ b=${b#.} a=;while [ "$b" ]
do c=${b:0:1};((c>0))&&o+=.$a$c+;b=${b:1};a+=0;done;};o=${o%+};echo ${o:-0}

Test:

exp() {
    o= a=${1%.*} b=${1#$a};while [ "$a" ];do c=${a:1};((${a%$c}>0))&&
    o+=${a%$c}${c//?/0}+;a=$c;done;[ "$b" ]&&{ b=${b#.} a=;while [ "$b" ]
    do c=${b:0:1};((c>0))&&o+=.$a$c+;b=${b:1};a+=0;done;};o=${o%+};echo ${o:-0}
}
while read num;do
    printf "%-12s => " $num
    exp $num
done <<<$'0\n6\n0.99\n24601\n6.283\n9000000.0000009\n3.1415\n.99'
0            => 0
6            => 6
0.99         => .9+.09
24601        => 20000+4000+600+1
6.283        => 6+.2+.08+.003
9000000.0000009 => 9000000+.0000009
3.1415       => 3+.1+.04+.001+.0005
.99          => .9+.09
\$\endgroup\$
2
\$\begingroup\$

Python, 131 bytes

f=lambda s,k=0,i=0,o="",z="0":s and f(s[1:],(s<z)+k,i+k,o+(s>="1")*([s[0]+~-(s+".").find(".")*z,"."+z*i+s[0]][k]+"+"))or o[:-1]or z

A really, really messy recursive function, probably not the best way to go about this. Input like f("10.0203").

\$\endgroup\$
1
  • \$\begingroup\$ Is this even Python? Love it. \$\endgroup\$
    – Ogaday
    Commented Jan 26, 2016 at 14:38
2
\$\begingroup\$

C, 155 153 161 bytes

+2 to link in the math library (source itself is 159).

main(d,v,p,q)char**v,*p,*q;{for(p=strchr(q=v[1],46),d=p?p-q:strlen(q);*q;++q)*q^46?printf(*q^48|q==v[1]?"%.*f%c":"",d<0?-d:0,(*q-48)*pow(10,--d),q[1]?43:0):0;}

Ungolfed

int main(int d, char **v, char *p, char *q)
{
    for(q = v[1], /* Cache the input string */
        p = strchr(q,'.'), /* find the decimal */
        d = p ? p-q : strlen(q); /* calculate number of digits before decimal */
        *q; /* loop while still input data */
        ++q) /* iterate to next character */
    {
        *q^46 /* if not at the decimal point... */
            ? printf(*q^48 || q == v[1] /* if not a zero, or if the string itself is zero... */
                ? "%.f%c" /* print the digit */
                : "", /* else print nothing */
                d<0 ? -d : 0, /* Calculate number of places after decimal to print */
                (*q-48)*pow(10,--d), /* Calculate the digit at the desired power of 10 */
                q[1]?43:0) /* If the next character is still valid input, print the '+' */
            : 0 /* else, do nothing */
    }
}
\$\endgroup\$
2
\$\begingroup\$

Dyalog APL, 47 bytes

{×⍎⍵:1↓∊'+',¨0~⍨(⍎¨w)×10*(⍵⍳'.')-1+⍳≢w←⍵~'.'⋄0} 

Takes number in character vector form, e.g. '123'.

Examples:

      f←{×⍎⍵:1↓∊'+',¨0~⍨(⍎¨w)×10*(⍵⍳'.')-1+⍳≢w←⍵~'.'⋄0} 
      ↑⍕¨f¨,¨'0' '6' '0.99' '24601' '6.283' '900000.000009'
0                     
6                     
0.9 + 0.09            
20000 + 4000 + 600 + 1
6 + 0.2 + 0.08 + 0.003
900000 + 0.000009     

Notes:
○ The reason for the modified last example is that APL, like some of the other submissions, by default will switch to scientific notation for such extreme numbers.
○ The phrase ↑⍕¨f¨,¨ is only needed to process all examples at once.

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

Retina, 113 bytes

Currently much longer than Martin's solution but uses a different method so I decided to post it.

^
x
S_`(?<=(.*)).(?=(.*))
x

¶\..*¶.*

$
¶
T`d`0`(?<=\d).*¶.*¶
(.*)¶(.*)¶
$2$1¶
(\..*?)0*¶
$1¶
\.?¶0*
¶
¶+
+
\+$
[empty line]

Try it online here.

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

perl, 132 bytes

131 +1 for -p switch.

This is based on my previous sed answer:

1while s/^([1-9]\d*)([1-9])(0*)([+.].*|)$/${1}0$3+$2$3$4/||s/([1-9]0*)\.([0-9])/$1+.$2/||s/\.(0*)([1-9])(\d*[1-9])$/.$1$2+.${1}0$3/

Test suite:

perl -pe'1while s/^([1-9]\d*)([1-9])(0*)([+.].*|)$/${1}0$3+$2$3$4/||
    s/([1-9]0*)\.([0-9])/$1+.$2/||s/\.(0*)([1-9])(\d*[1-9])$/.$1$2+.${1}0$3/
' <<<$'0\n6\n0.99\n24601\n6.283\n9000000.0000009\n3.1415'
0
6
0.9+.09
20000+4000+600+1
6+.2+.08+.003
9000000+.0000009
3+.1+.04+.001+.0005
\$\endgroup\$
1
\$\begingroup\$

Powershell - 172 166 193 bytes

All on a single line:

$z=([string]$args[0])-split"\.";$y=$z[0].length-1+0.6;($z|%{$x=[char[]]$_;if($y-gt0){($x|%{$_+"0"*(-1+$y--)})}else{($x|%{"0."+"0"*[math]::abs($y--)+$_})}}|?{-not($_-match'^[0.]+$')})-join' + '

Ungolfed:

$z=([string]$args[0]) -split "\."
$y=$z[0].length-1+0.6
($z | %{
    $x=[char[]]$_
    if($y -gt 0) {
        ($x | %{$_+"0"*(-1+$y--)})
    } else {
        ($x | %{"0."+"0"*[math]::abs($y--)+$_})
    }
} | ?{ -not($_ -match '^[0.]+$')}) -join ' + '

Test cases, plus one additional:

PS> (0, 6, 0.99, 24601, 6.283, 9000000.0000009, [math]::pi) | %{.\expand.ps1 $_}

6
0.9 + 0.09
20000 + 4000 + 600 + 1
6 + 0.2 + 0.08 + 0.003
9000000 + 0.0000009
3 + 0.1 + 0.04 + 0.001 + 0.0005 + 0.00009 + 0.000002 + 0.0000006 + 0.00000005 + 0.000000003 + 0.0000000005 + 0.00 000000008 + 0.000000000009 + 0.0000000000007 + 0.00000000000009    
PS>
\$\endgroup\$
2
1
\$\begingroup\$

Perl, 248 bytes

Ew, I am noobish at Perl golfing.

@a=split/\./,<>;
@b=split``,$a[1];
@c=split``,$a[0];
for($i=0;$i<length$a[0];$i++){
   $_.=($c[$i]!=0)?$c[$i]."0"x((length$a[0])-$i-2)."+":"";
}
for($i=1;$i<=length$a[1];$i++){
   $_.=($b[$i-1]!=0)?"0."."0"x($i-1).$b[$i-1]."+":"";
}
chop;
($_=="")?print"0 ":print;

Try it here.

\$\endgroup\$
9
  • \$\begingroup\$ This seem not work with integer numbers. \$\endgroup\$ Commented Jan 20, 2016 at 13:40
  • \$\begingroup\$ I put the wrong Ideone link. It doesn't take into account changes made in Edit mode. :( It should work now. \$\endgroup\$
    – Sake
    Commented Jan 20, 2016 at 13:54
  • \$\begingroup\$ You have an error somewhere: when I enter 5 it return 50. \$\endgroup\$ Commented Jan 20, 2016 at 16:29
  • \$\begingroup\$ Strange, since I tested 5 with the link I provided yesterday after you put your first comment. Mind trying now ? (I changed the link again) \$\endgroup\$
    – Sake
    Commented Jan 21, 2016 at 9:26
  • \$\begingroup\$ I just tested your script on my perl interpreter (v5.20.2) \$\endgroup\$ Commented Jan 21, 2016 at 13:44
1
\$\begingroup\$

Java, 284 244 243 Bytes

String x(String s){int b=s.length(),d=(d=s.indexOf(46))<0?b:d,i=-1,k=0;String o="";for(char c;++i<b;)o+=(c=s.charAt(i))>48?(k++>0?" + ":"")+(d-i>0?c:"0.")+new String(new char[Math.abs(d-i)-1]).replace('\0','0')+(d-i>0?"":c):"";return b<2?s:o;}

Unfortunately, I could not find a shorter way of creating repeating Strings than:

  • build a char[] of the required length
  • use Arrays.fill to set the characters
  • use new String so it can be concatenated

With inspiration by @Khaled A Khunaifer, I could shave off 40 Bytes.

Edit: indexOf takes an int, so I could replace '.' with 46. Unfortunately, this does not seem to be possible with replace.

\$\endgroup\$
4
  • \$\begingroup\$ I managed to shrink it down to 250, check ideone.com/HqLnMo \$\endgroup\$
    – Khaled.K
    Commented Jan 19, 2016 at 9:21
  • \$\begingroup\$ @Khaled A Khunaifer Your solution seems to have problems with single digit test cases. But I like your way of generating the zeros. \$\endgroup\$
    – ECS
    Commented Jan 19, 2016 at 9:39
  • \$\begingroup\$ fix this .replace('\0','0') function replace expect String not char, it should be .replace("\0","0") \$\endgroup\$
    – Khaled.K
    Commented Jan 19, 2016 at 10:20
  • \$\begingroup\$ @Khaled A Khunaifer It works in my test cases, also docs.oracle.com/javase/8/docs/api/java/lang/… \$\endgroup\$
    – ECS
    Commented Jan 19, 2016 at 10:24
1
\$\begingroup\$

Python, 125 bytes

After deleting my 1st answer (sry!) which could not handle small numbers due to machine epsilon issues, I found a different solution. It handles float as well as integers, trailing zeros (!) and is written as function.

Thanks to @ogaday for the useful hints and for the compact '0'-fix!

Golfed:

def f(x):x+='.';i=x.find('.');z=list(x);del z[i];return'+'.join([str(int(o)*10**(i-j-1))for j,o in enumerate(z)if'0'<o])or'0'

Ungolfed:

def f(x):
  x+='.'
  i=x.find('.')
  z=list(x)
  del z[i]   
  return '+'.join([str(int(o)*10**(i-j-1)) for j,o in enumerate(z) if '0'<o]) or '0'

Usage:

>>> f("0")
'0'

>>> f("32.005")
'30+2+0.005'

>>> f("100020003000009000000.0007")
'100000000000000000000+20000000000000000+3000000000000+9000000+0.0007'

>>> f("1000000000009000000.0007000000000000000002")
'1000000000000000000+9000000+0.0007+2e-22'

>>> f("0001.99")
'1+0.9+0.09'
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Nice. Fails the f('0') test case however, and when I copy and paste straight into my interpreter I get the scientific notation (which I think is fine). Also, list(c) is shorter. If you concatenate the '.' before turning it into a list you don't need to add [] either. Using find instead of index on the string before turning it into a list, after adding '.' also saves you a byte. Reordering the inequality allows you to remove an additional space too: def f(x):x+='.';i=x.find('.');z=list(x);del z[i];return"+".join([str(int(o)*10**(i-j-1))for j,o in enumerate(z)if"0"<o])or'0' \$\endgroup\$
    – Ogaday
    Commented Jan 26, 2016 at 15:24
1
\$\begingroup\$

CoffeeScript, 144 bytes

Straight forward solution:

X=(n)->[m,k]="#{n}".split '.';(c+Array(m.length-i).join 0for i,c of m when+c).concat(".#{Array(++i).join 0}"+c for i,c of k when+c).join('+')||0

Executable:

<script src="http://coffeescript.org/extras/coffee-script.js"></script>
<script type="text/coffeescript">
X=(n)->[m,k]="#{n}".split '.';(c+Array(m.length-i).join 0for i,c of m when+c).concat(".#{Array(++i).join 0}"+c for i,c of k when+c).join('+')||0

# Tests follow
tests = [
  0
  6
  0.99
  24601
  6.283
  9000000.0000009
]

window.solution = X
result.textContent=("#{n} => #{X n}" for n in tests).join '\n'
</script>
<input type="number" oninput="result.textContent=solution(this.value)">
<pre id="result"></pre>

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

Stax, 18 bytes

ºî≤FlφLfÜG→\ΦUq╜♥←

Run and debug it

Unpacked, ungolfed, and commented, it looks like this.

c           copy input
!C          terminate if input is falsy
y{          for each character in the string input...
  y.\d'0R   replace each digit in the input with "0"
  ia&       then replace the nth character back to its original value
  e         eval as float
m           map using block to produce array
{f          filter out zeroes
'+*         join with "+"

Run this one

Like the many of the other solutions posted, it produces 9000000+9e-7 for the last test case. According to established precedent this is allowed because the test case is too precise for the language.

\$\endgroup\$
0
\$\begingroup\$

Lua, 350 Bytes

I think there's two way to golf it down further :

  • I could make use of macro.define to replace some of the commons expressions (can't test right now, and not sure it would make me gain some bytes)

  • Use split on the dot instead of iterating on the whole string. Once again, I'm not sure it would reduce the size of this function, as manipulating string in lua is quite painful.

function f(s)v,r=s:find("%.")or#s+1,""if #s==1 then return s end for i=1,#s do a=""(v>i and s:sub(i,v-1)or s:sub(v,i)):gsub(".",function(c)a=a..(not a:find(c)and(c==s:sub(i,i)or c==".")and c or 0)end)s,r=v<i and s:sub(0,i-1).."0"..s:sub(i+1,#s)or s,r..((#a==a:find("%.")or tonumber(a)==0)and""or a:gsub("%.","0.")..(i~=#s and"+"or""))end return r end

Explanations

function f(s)
  v=s:find("%.")or #s+1               -- v=index of the dot in a decimal number
  r=""                                -- v=#s+1 when s is an integer(v=0 would screw sub())
  if #s==1 then return s end          -- exit if s is a single digit
  for i=1,#s                          -- iterate over s
  do
    a=""

    (v>i and s:sub(i,v-1)or s:sub(v,i)-- only send the integer OR decimal part to gsub
      ):gsub(".",function(c)          -- iterate over each character of s:sub()

    -- a contains the next number to be concatenated to the string r(the one to be returned)
      a=a..(not a:find(c)             -- we concatenate a with c if a doen't contains
        and(c==s:sub(i,i)or c==".")   -- c, and c is either a dot, or the next number
             and c or 0)              -- to be add, we put a 0 otherwise
    end)
    -- we concatenate the new a with the string already formed
    r=r..((#a==a:find("%.")           -- if a=="." or a's value is 0
            or tonumber(a)==0)and""   -- we concatenate an empty string
      or a:gsub("%.","0.")            -- else, we replace the (possible) leading dot by "0."
      ..(i~=#s and"+"or""))           -- and concatenate a "+" if it isn't the last number to be added

    s=v<i and s:sub(0,i-1)            -- We then replace the digit we have worked with
      .."0"..s:sub(i+1,#s)or s        -- to prevent duplicates
  end
  return r
end

You can test lua online and use the following source code to run it with some test cases

function f(s)v,r=s:find("%.")or#s+1,""if #s==1 then return s end for i=1,#s do a=""(v>i and s:sub(i,v-1)or s:sub(v,i)):gsub(".",function(c)a=a..(not a:find(c)and(c==s:sub(i,i)or c==".")and c or 0)end)s,r=v<i and s:sub(0,i-1).."0"..s:sub(i+1,#s)or s,r..((#a==a:find("%.")or tonumber(a)==0)and""or a:gsub("%.","0.")..(i~=#s and"+"or""))end return r end

print(f("3123.12333"))
print(f("9545"))
print(f("9000000.0000009"))
print(f("6"))
\$\endgroup\$
0
\$\begingroup\$

C, 253 bytes

m(char*i){int k,j=0,s=0,d=0;while(i[s])s++;while(i[d]!=46)d++;while(j<d){if(i[j]!=48){for(k=0;k<(d-j);k++)putchar(k?48:i[j]);putchar(43);}j++;}while(++j<s)if(i[j]!=48){putchar(46);for(k=0;k<(j-d);k++)putchar(k==(j-d-1)?i[j]:48);putchar(43);}putchar(8);}

Note: putchar(8) should perform a backspace.

 Input: 1230.0456
Output: 1000+200+30+.04+.005+.0006

Detailed, try here

while(i[s]) s++;
while(i[d]!=46) d++;

while (j<d)
{
    if (i[j]!='0')
    {
        for(k=0;k<(d-j);k++) putchar(k? '0': i[j]);
        putchar(43);
    }
    j++;
}

while (++j<s)
if (i[j]!='0')
{
    putchar(46);
    for(k=0; k<(j-d); k++) putchar(k==(j-d-1)? i[j]: '0');
    putchar(43);
}

putchar(8);
\$\endgroup\$
0
\$\begingroup\$

sed, 136 128 bytes

Reduced by 8 chars by dropping spaces and useless 0.

:;s/^([1-9][0-9]*)([1-9])(0*)([+.].*|)$/\10\3+\2\3\4/;s/([1-9]0*)\.([0-9])/\1+.\2/;s/\.(0*)([1-9])([0-9]*[1-9])$/.\1\2+.\10\3/;t

Test cases:

sed -r ':;
    s/^([1-9][0-9]*)([1-9])(0*)([+.].*|)$/\10\3+\2\3\4/;
    s/([1-9]0*)\.([0-9])/\1+.\2/;
    s/\.(0*)([1-9])([0-9]*[1-9])$/.\1\2+.\10\3/;
    t' <<<$'0\n6\n0.99\n24601\n6.283\n9000000.0000009\n3.1415'
0
6
0.9+.09
20000+4000+600+1
6+.2+.08+.003
9000000+.0000009
3+.1+.04+.001+.0005
\$\endgroup\$
0
\$\begingroup\$

JavaScript (ES7), 114 bytes

s=>(p=s.search(/.\b/),i=-1,[for(c of s)if((i++,c>0))(z=s.substring(i,p).replace(/d/g,0),i<p?c+z:z+c)].join`+`||s

Works with arbitrary length numbers because it uses string manipulation throughout.

Without the array comprehension (122 bytes):

s=>[...s].map((c,i)=>c<'1'?'':(z=s.substring(i,p).replace(/\d/g,0),i<p?c+z:z+c),p=s.search(/.\b/)).filter(x=>x).join`+`||s

Ungolfed:

function expand(s) {
    zeros = s.replace(/\d/g, "0");
    point = s.indexOf(".");
    if (point < 0) point = s.length;
    result = [];
    for (i = 0; i < s.length; i++) {
        if (s[i] > "0") {
            if (i < point) result.push(s[i] + zeros.slice(i, point - 1));
            else result.push(zeros.slice(point - 1, i) + s[i]);
         }
     }
     return result.length ? result.join("+") : s;
}
\$\endgroup\$
2
  • \$\begingroup\$ As far as I know, this new array comprehension syntax is from ECMAScript 7. \$\endgroup\$
    – manatwork
    Commented Jan 22, 2016 at 11:11
  • \$\begingroup\$ @manatwork Thanks, I updated it while I was adding the ungolfed version. \$\endgroup\$
    – Neil
    Commented Jan 22, 2016 at 11:20
0
\$\begingroup\$

R - 133 bytes

Robust, ignores Machine Epsilon and works also with trailing zeros.

a) Golfed:

f=function(x)if(x=='0')x else{z=strsplit(x,'')[[1]];i=which(z=='.');n=as.numeric(z[-i])*10^(i-seq(z)[-1]);paste(n[n>0],collapse='+')}

Ungolfed:

f=function(x)
  if(x=='0') 
    x 
  else {
    z=strsplit(x,'')[[1]]
    i=which(z=='.')   
    n=as.numeric(z[-i])*10^(i-seq(z)[-1])  
    paste(n[n>0],collapse='+')
  }

Usage:

f("900.008")
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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