Sum multiples of 3 and 5: Difference between revisions
Content added Content deleted
(→{{header|Ruby}}: use sum method) |
(→JS ES6: Tidied code, added formatting for output.) |
||
Line 1,827: | Line 1,827: | ||
<lang JavaScript>(() => { |
<lang JavaScript>(() => { |
||
// |
// sum35 :: Int -> Int |
||
const sum35 = n => { |
|||
// The sum of all positive multiples of |
|||
// 3 or 5 below n. |
|||
const f = sumMults(n); |
|||
return f(3) + f(5) - f(15); |
|||
}; |
|||
// sumMults :: Int -> Int -> Int |
// sumMults :: Int -> Int -> Int |
||
const sumMults = |
const sumMults = n => |
||
// Area under straight line |
|||
// between first multiple and last. |
|||
factor => { |
|||
const n1 = quot(n - 1)(factor); |
|||
return quot(factor * n1 * (n1 + 1))(2); |
|||
}; |
|||
// ------------------------- TEST -------------------------- |
|||
// sum35 :: Int -> Int |
|||
const sum35 = n => sumMults(n, 3) + sumMults(n, 5) - sumMults(n, 15); |
|||
// main :: IO () |
|||
const main = () => |
|||
fTable('Sums for n = 10^1 thru 10^8:')(str)(str)( |
|||
sum35 |
|||
)( |
|||
enumFromTo(1)(8) |
|||
.map(n => Math.pow(10, n)) |
|||
); |
|||
// GENERIC ---------------------------------------------------------------- |
|||
// ------------------------ GENERIC ------------------------ |
|||
// enumFromTo :: Int -> Int -> [Int] |
// enumFromTo :: Int -> Int -> [Int] |
||
const enumFromTo = |
const enumFromTo = m => |
||
n => !isNaN(m) ? ( |
|||
Array.from({ |
|||
length: 1 + n - m |
|||
}, (_, i) => m + i) |
|||
) : enumFromTo_(m)(n); |
|||
// quot :: Int -> Int -> Int |
|||
const quot = n => |
|||
m => Math.floor(n / m); |
|||
// ------------------------ DISPLAY ------------------------ |
|||
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c |
|||
const compose = (...fs) => |
|||
// A function defined by the right-to-left |
|||
// composition of all the functions in fs. |
|||
fs.reduce( |
|||
(f, g) => x => f(g(x)), |
|||
x => x |
|||
); |
|||
// fTable :: String -> (a -> String) -> (b -> String) |
|||
// -> (a -> b) -> [a] -> String |
|||
const fTable = s => |
|||
// Heading -> x display function -> |
|||
// fx display function -> |
|||
// f -> values -> tabular string |
|||
xShow => fxShow => f => xs => { |
|||
const |
|||
ys = xs.map(xShow), |
|||
w = Math.max(...ys.map(length)); |
|||
return s + '\n' + zipWith( |
|||
a => b => a.padStart(w, ' ') + ' -> ' + b |
|||
)(ys)( |
|||
xs.map(x => fxShow(f(x))) |
|||
).join('\n'); |
|||
}; |
|||
// length :: [a] -> Int |
|||
const length = xs => |
|||
// Returns Infinity over objects without finite |
|||
// length. This enables zip and zipWith to choose |
|||
// the shorter argument when one is non-finite, |
|||
// like cycle, repeat etc |
|||
'GeneratorFunction' !== xs.constructor.constructor.name ? ( |
|||
xs.length |
|||
) : Infinity; |
|||
// list :: StringOrArrayLike b => b -> [a] |
|||
const list = xs => |
|||
// xs itself, if it is an Array, |
|||
// or an Array derived from xs. |
|||
Array.isArray(xs) ? ( |
|||
xs |
|||
) : Array.from(xs); |
|||
// str :: a -> String |
|||
const str = x => |
|||
Array.isArray(x) && x.every( |
|||
v => ('string' === typeof v) && (1 === v.length) |
|||
) ? ( |
|||
x.join('') |
|||
) : x.toString(); |
|||
// take :: Int -> [a] -> [a] |
|||
// take :: Int -> String -> String |
|||
const take = n => |
|||
// The first n elements of a list, |
|||
// string of characters, or stream. |
|||
xs => 'GeneratorFunction' !== xs |
|||
.constructor.constructor.name ? ( |
|||
xs.slice(0, n) |
|||
) : [].concat.apply([], Array.from({ |
|||
length: n |
|||
}, () => { |
|||
const x = xs.next(); |
|||
return x.done ? [] : [x.value]; |
|||
})); |
|||
// Integral a => a -> a -> a |
|||
const quot = (n, m) => Math.floor(n / m); |
|||
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] |
|||
// TEST ------------------------------------------------------------------- |
|||
const zipWith = f => |
|||
// Use of `take` and `length` here allows zipping with non-finite lists |
|||
// i.e. generators like cycle, repeat, iterate. |
|||
xs => ys => { |
|||
const n = Math.min(length(xs), length(ys)); |
|||
return (([as, bs]) => Array.from({ |
|||
length: n |
|||
}, (_, i) => f(as[i])( |
|||
bs[i] |
|||
)))([xs, ys].map( |
|||
compose(take(n), list) |
|||
)); |
|||
}; |
|||
// |
// --- |
||
return |
return main(); |
||
.map(n => Math.pow(10, n)) |
|||
.reduce((a, x) => ( |
|||
a[x.toString()] = sum35(x), |
|||
a |
|||
), {}); |
|||
})();</lang> |
})();</lang> |
||
{{Out}} |
{{Out}} |
||
<pre>Sums for n = 10^1 thru 10^8: |
|||
<lang JavaScript>{"10":23, "100":2318, "1000":233168, "10000":23331668, |
|||
10 -> 23 |
|||
"100000":2333316668, "1000000":233333166668, "10000000":23333331666668, |
|||
100 -> 2318 |
|||
"100000000":2333333316666668}</lang> |
|||
1000 -> 233168 |
|||
10000 -> 23331668 |
|||
100000 -> 2333316668 |
|||
1000000 -> 233333166668 |
|||
10000000 -> 23333331666668 |
|||
100000000 -> 2333333316666668</pre> |
|||
=={{header|jq}}== |
=={{header|jq}}== |