127 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			127 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
|   | --- | ||
|  | id: 5949b579404977fbaefcd737 | ||
|  | title: Amicable pairs | ||
|  | challengeType: 5 | ||
|  | forumTopicId: 302225 | ||
|  | dashedName: amicable-pairs | ||
|  | --- | ||
|  | 
 | ||
|  | # --description--
 | ||
|  | 
 | ||
|  | Two integers $N$ and $M$ are said to be [amicable pairs](https://en.wikipedia.org/wiki/Amicable numbers "wp: Amicable numbers") if $N \\neq M$ and the sum of the [proper divisors](https://rosettacode.org/wiki/Proper divisors "Proper divisors") of $N$ ($\\mathrm{sum}(\\mathrm{propDivs}(N))$) $= M$ as well as $\\mathrm{sum}(\\mathrm{propDivs}(M)) = N$. | ||
|  | 
 | ||
|  | **Example:** | ||
|  | 
 | ||
|  | **1184** and **1210** are an amicable pair, with proper divisors: | ||
|  | 
 | ||
|  | <ul> | ||
|  |   <li>1, 2, 4, 8, 16, 32, 37, 74, 148, 296, 592  and</li> | ||
|  |   <li>1, 2, 5, 10, 11, 22, 55, 110, 121, 242, 605   respectively.</li> | ||
|  | </ul> | ||
|  | 
 | ||
|  | # --instructions--
 | ||
|  | 
 | ||
|  | Calculate and show here the Amicable pairs below 20,000 (there are eight). | ||
|  | 
 | ||
|  | # --hints--
 | ||
|  | 
 | ||
|  | `amicablePairsUpTo` should be a function. | ||
|  | 
 | ||
|  | ```js | ||
|  | assert(typeof amicablePairsUpTo === 'function'); | ||
|  | ``` | ||
|  | 
 | ||
|  | `amicablePairsUpTo(300)` should return `[[220,284]]`. | ||
|  | 
 | ||
|  | ```js | ||
|  | assert.deepEqual(amicablePairsUpTo(300), answer300); | ||
|  | ``` | ||
|  | 
 | ||
|  | `amicablePairsUpTo(3000)` should return `[[220,284],[1184,1210],[2620,2924]]`. | ||
|  | 
 | ||
|  | ```js | ||
|  | assert.deepEqual(amicablePairsUpTo(3000), answer3000); | ||
|  | ``` | ||
|  | 
 | ||
|  | `amicablePairsUpTo(20000)` should return `[[220,284],[1184,1210],[2620,2924],[5020,5564],[6232,6368],[10744,10856],[12285,14595],[17296,18416]]`. | ||
|  | 
 | ||
|  | ```js | ||
|  | assert.deepEqual(amicablePairsUpTo(20000), answer20000); | ||
|  | ``` | ||
|  | 
 | ||
|  | # --seed--
 | ||
|  | 
 | ||
|  | ## --after-user-code--
 | ||
|  | 
 | ||
|  | ```js | ||
|  | const answer300 = [[220, 284]]; | ||
|  | const answer3000 = [ | ||
|  |   [220, 284], | ||
|  |   [1184, 1210], | ||
|  |   [2620, 2924] | ||
|  | ]; | ||
|  | const answer20000 = [ | ||
|  |   [220, 284], | ||
|  |   [1184, 1210], | ||
|  |   [2620, 2924], | ||
|  |   [5020, 5564], | ||
|  |   [6232, 6368], | ||
|  |   [10744, 10856], | ||
|  |   [12285, 14595], | ||
|  |   [17296, 18416] | ||
|  | ]; | ||
|  | ``` | ||
|  | 
 | ||
|  | ## --seed-contents--
 | ||
|  | 
 | ||
|  | ```js | ||
|  | function amicablePairsUpTo(maxNum) { | ||
|  | 
 | ||
|  |   return true; | ||
|  | } | ||
|  | ``` | ||
|  | 
 | ||
|  | # --solutions--
 | ||
|  | 
 | ||
|  | ```js | ||
|  | // amicablePairsUpTo :: Int -> [(Int, Int)] | ||
|  | function amicablePairsUpTo(maxNum) { | ||
|  |   return range(1, maxNum) | ||
|  |     .map(x => properDivisors(x) | ||
|  |       .reduce((a, b) => a + b, 0)) | ||
|  |     .reduce((a, m, i, lst) => { | ||
|  |       const n = i + 1; | ||
|  | 
 | ||
|  |       return (m > n) && lst[m - 1] === n ? | ||
|  |         a.concat([ | ||
|  |           [n, m] | ||
|  |         ]) : a; | ||
|  |     }, []); | ||
|  | } | ||
|  | 
 | ||
|  | // properDivisors :: Int -> [Int] | ||
|  | function properDivisors(n) { | ||
|  |   if (n < 2) return []; | ||
|  | 
 | ||
|  |   const rRoot = Math.sqrt(n); | ||
|  |   const intRoot = Math.floor(rRoot); | ||
|  |   const blnPerfectSquare = rRoot === intRoot; | ||
|  |   const lows = range(1, intRoot) | ||
|  |   .filter(x => (n % x) === 0); | ||
|  | 
 | ||
|  |   return lows.concat(lows.slice(1) | ||
|  |     .map(x => n / x) | ||
|  |     .reverse() | ||
|  |     .slice(blnPerfectSquare | 0)); | ||
|  | } | ||
|  | 
 | ||
|  | // Int -> Int -> Maybe Int -> [Int] | ||
|  | function range(m, n, step) { | ||
|  |   const d = (step || 1) * (n >= m ? 1 : -1); | ||
|  | 
 | ||
|  |   return Array.from({ | ||
|  |     length: Math.floor((n - m) / d) + 1 | ||
|  |   }, (_, i) => m + (i * d)); | ||
|  | } | ||
|  | ``` |