How NOT to reduce fractions
Haskell, 207 206 (209?) characters
import Data.List
x![]=[x];(w:x)!(y:z)|w==y=x!z;_!_=[]
a@(w:x)%b=a!b++[w:e|e<-x%b];a%b=a!b
h=show
f n=[(c,n-c)|c<-[1..n-1],i<-inits$h c,s<-init$tails i,s/=h c,a<-h c%s,b<-h(n-c)%s,read a*(n-c)==read('0':b)*c]
If it's not allowable to return the same ratio more than once (400/400 = 40/40 = 4/4), use f n=nub[...
to filter them out.
Returns a list of pairs. A list of two-element pairs costs the same. A list of actual fractions would require importing Data.Ratio
or fully qualifying Data.Ratio.%
(which also collides with the %
function defined here)
test cases (with nub
):
Prelude Data.List> f 80
[(10,70),(16,64),(20,60),(30,50),(40,40),(50,30),(60,20),(64,16),(70,10)]
Prelude Data.List> f 147
[(49,98),(98,49)]
Prelude Data.List> f 500
[(10,490),(20,480),(30,470),(40,460),(50,450),(60,440),(70,430),(80,420),(90,410
),(100,400),(110,390),(120,380),(130,370),(140,360),(150,350),(160,340),(170,330
),(180,320),(190,310),(200,300),(210,290),(220,280),(230,270),(240,260),(250,250
),(260,240),(270,230),(280,220),(290,210),(300,200),(310,190),(320,180),(330,170
),(340,160),(350,150),(360,140),(370,130),(380,120),(390,110),(400,100),(410,90)
,(420,80),(430,70),(440,60),(450,50),(460,40),(470,30),(480,20),(490,10)]
ungolfed and commented:
import Data.List
-- haystack ! needle - the haystack with the needle removed, wrapped in a single-element list
-- or an empty array if the haystack does not start with the needle
x ! [] = [x] -- case: empty needle = match with the full haystack left
(h:hs) ! (n:ns) | h == n = hs ! ns -- case: needle and haystack match
_ ! _ = [] -- case: no match
-- haystack % needle - the haystack with the needle removed
-- for all positions of the needle in the haystack
a@(h:hs) % b = a ! b ++ map (h:) (hs%b) -- either remove the needle here, or elsewhere
a % b = a -- empty haystack cannot be popped
-- f - the function we are interested in
f total = [ (num, total - num)
| num <- [1 .. total-1], -- for each numerator in range
i <- inits $ show num, -- for each postfix of the numerator
sub <- init $ tails i, -- for each prefix of the postfix except the last (empty) one
sub /= show num, -- that isn't equal to the numerator
reNum <- show num % sub, -- remove the substring from the numerator
reDiv <- show (total - num) % sub, -- as well as from the denominator.
-- the resulting ratios must be equal by value:
(read reNum) ^ (total - num) == (read '0':reDiv) * num]
Python 2 – 183 180
r=range
s=lambda a:[(a[i:j],int(a[:i]+a[j:]))for i in r(len(a))for j in r(i+1,len(a)+(i>0))]
l=sum([[a,n-a]for a in r(n)for p,x in s(`a`)for q,y in s(`n-a`)if(n-a)*x==a*y<p==q],[])
the input must be stored in n
, the output will be stored in l
.
Test cases:
n = 80:
[10, 70, 16, 64, 20, 60, 30, 50, 40, 40, 40, 40, 50, 30, 60, 20, 64, 16, 70, 10]
n = 147:
[49, 98, 98, 49]
n =490:
[10, 480, 20, 470, 30, 460, 40, 450, 50, 440, 60, 430, 70, 420, 80, 410, 90, 400, 90, 400, 98, 392, 100, 390, 100, 390, 110, 380, 120, 370, 130, 360, 140, 350, 150, 340, 160, 330, 170, 320, 180, 310, 190, 300, 190, 300, 196, 294, 200, 290, 200, 290, 210, 280, 220, 270, 230, 260, 240, 250, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 250, 240, 260, 230, 270, 220, 280, 210, 290, 200, 290, 200, 294, 196, 300, 190, 300, 190, 310, 180, 320, 170, 330, 160, 340, 150, 350, 140, 360, 130, 370, 120, 380, 110, 390, 100, 390, 100, 392, 98, 400, 90, 400, 90, 410, 80, 420, 70, 430, 60, 440, 50, 450, 40, 460, 30, 470, 20, 480, 10]
Should duplicates in the output be forbidden, it gets 10 characters longer:
r=range
s=lambda a:[(a[i:j],int(a[:i]+a[j:]))for i in r(len(a))for j in r(i+1,len(a)+(i>0))]
l=sum(map(list,{(a,n-a)for a in r(n)for p,x in s(`a`)for q,y in s(`n-a`)if(n-a)*x==a*y<p==q}),[])