Water collected between towers: Difference between revisions

→‎JS :: ES6: Tidied, updated primitives.
(Added Tailspin solution)
(→‎JS :: ES6: Tidied, updated primitives.)
Line 1,289:
<lang JavaScript>(() => {
'use strict';
 
// ---------- WATER COLLECTED BETWEEN TOWERS -----------
 
// waterCollected :: [Int] -> Int
const waterCollected = xs => {
constsum(filter(lt(0))(
maxToRight = scanr1zipWith(subtract)(max, xs),(
maxToLeft = scanl1(max, xs zipWith(min),(
levels = zipWith(min, maxToLeft, maxToRight scanl1(max)(xs);
return sum )(
zipWith(difference, levels, scanr1(max)(xs)
.filter(x => x > 0)
);
} ));
 
 
// GENERIC FUNCTIONS ----------------------------- TEST ------------------------
const main = () => [
[1, 5, 3, 7, 2],
[5, 3, 7, 2, 6, 4, 5, 9, 1, 2],
[2, 6, 3, 5, 2, 8, 1, 4, 2, 2, 5, 3, 5, 7, 4, 1],
[5, 5, 5, 5],
[5, 6, 7, 8],
[8, 7, 7, 6],
[6, 7, 10, 7, 6]
].map(waterCollected);
 
 
// ---------------------- GENERIC ----------------------
 
// Tuple (,) :: a -> b -> (a, b)
const Tuple = a =>
b => ({
type: 'Tuple',
'0': a,
'1': b,
length: 2
});
 
 
// filter :: (a -> Bool) -> [a] -> [a]
const filter = p =>
// The elements of xs which match
// the predicate p.
xs => [...xs].filter(p);
 
 
// gt :: Ord a => a -> a -> Bool
const gt = x => y =>
'Tuple' === x.type ? (
x[0] > y[0]
) : (x > y);
 
 
// 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;
 
 
// lt (<) :: Ord a => a -> a -> Bool
const lt = a =>
b => a < b;
 
// difference :: (Num a) => a -> a -> a
const difference = (a, b) => a - b;
 
// max :: Ord a => a -> a -> a
const max = (a, b) => a > b ? a : b;
// b if its greater than a,
// otherwise a.
b => a > b ? a : b;
 
 
// min :: Ord a => a -> a -> a
const min = (a, b) => b < a ? b : a;
b => b < a ? b : a;
 
 
// scanl :: (b -> a -> b) -> b -> [a] -> [b]
const scanl = (f, => startValue, => xs) => {
constxs.reduce((a, lstx) => [startValue];{
return const v = f(a[0])(x);
xs.reducereturn Tuple(v)(a, x[1].concat(v) => {);
}, Tuple(startValue)([startValue]))[1];
const v = f(a, x);
 
return (lst.push(v), v);
}, startValue),
lst
);
};
 
// scanl1 is a variant of scanl that has no starting value argument
// scanl1 :: (a -> a -> a) -> [a] -> [a]
const scanl1 = (f, xs) =>
xs.length// >scanl1 0is ?a variant of scanl(f, xs[0],that xs.slice(1))has :no [];
// starting value argument.
xs => xs.length > 0 ? (
scanl(f)(
xs[0]
)(xs.slice(1))
) : [];
 
 
// scanr :: (b -> a -> b) -> b -> [a] -> [b]
const scanr = (f, startValue, xs) => {
conststartValue lst=> xs => [startValue];xs.reduceRight((a, x) => {
return const v = f(x)(a[0]);
xs.reduceRightreturn Tuple(v)([v].concat(a, x[1]) => {);
}, Tuple(startValue)([startValue]))[1];
const v = f(a, x);
 
return (lst.push(v), v);
}, startValue),
lst.reverse()
);
};
 
// scanr1 is a variant of scanr that has no starting value argument
// scanr1 :: (a -> a -> a) -> [a] -> [a]
const scanr1 = (f, xs) =>
xs.length// >scanr1 0is ?a scanr(f,variant xs.slice(-1)[0],of scanr xs.slice(0,that -1))has :no [];
// seed-value argument, and assumes that
// xs is not empty.
xs => xs.length > 0 ? (
scanr(f)(
xs.slice(-1)[0]
)(xs.slice(0, -1))
) : [];
 
// sum :: (Num a) => [a] -> a
const sum = xs => xs.reduce((a, x) => a + x, 0);
 
// zipWithsubtract :: (aNum -> bNum -> c) -> [a] -> [b] -> [c]Num
const zipWithsubtract = (f, xs, ys)x => {
const nyy => y - ys.lengthx;
return (xs.length <= ny ? xs : xs.slice(0, ny))
.map((x, i) => f(x, ys[i]));
};
 
// TEST ------------------------------------------------------------------
return [
[1, 5, 3, 7, 2],
[5, 3, 7, 2, 6, 4, 5, 9, 1, 2],
[2, 6, 3, 5, 2, 8, 1, 4, 2, 2, 5, 3, 5, 7, 4, 1],
[5, 5, 5, 5],
[5, 6, 7, 8],
[8, 7, 7, 6],
[6, 7, 10, 7, 6]
].map(waterCollected);
 
//--> [2,sum 14,:: 35,[Num] 0,-> 0, 0, 0]Num
const sum = xs =>
// The numeric sum of all values in xs.
xs.reduce((a, x) => a + x, 0);
 
 
// take :: Int -> [a] -> [a]
const take = n =>
// The first n elements of a list,
// string of characters, or stream.
xs => xs.slice(0, n);
 
 
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
const zipWith = f =>
// A list constructed by zipping with a
// custom function, rather than with the
// default tuple constructor.
xs => ys => ((xs_, ys_) => {
const lng = Math.min(length(xs_), length(ys_));
return take(lng)(xs_).map(
(x, i) => f(x)(ys_[i])
);
})(xs, ys);
 
// MAIN ---
return main();
})();</lang>
{{Out}}
9,655

edits