Water collected between towers: Difference between revisions
Content added Content deleted
(Added Tailspin solution) |
(→JS :: ES6: Tidied, updated primitives.) |
||
Line 1,289: | Line 1,289: | ||
<lang JavaScript>(() => { |
<lang JavaScript>(() => { |
||
'use strict'; |
'use strict'; |
||
// ---------- WATER COLLECTED BETWEEN TOWERS ----------- |
|||
// waterCollected :: [Int] -> Int |
// waterCollected :: [Int] -> Int |
||
const waterCollected = xs => |
const waterCollected = xs => |
||
sum(filter(lt(0))( |
|||
zipWith(subtract)(xs)( |
|||
zipWith(min)( |
|||
scanl1(max)(xs) |
|||
)( |
|||
scanr1(max)(xs) |
|||
) |
|||
) |
) |
||
)); |
|||
// |
// ----------------------- 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 |
// max :: Ord a => a -> a -> a |
||
const max = |
const max = a => |
||
// b if its greater than a, |
|||
// otherwise a. |
|||
b => a > b ? a : b; |
|||
// min :: Ord a => a -> a -> a |
// min :: Ord a => a -> a -> a |
||
const min = |
const min = a => |
||
b => b < a ? b : a; |
|||
// scanl :: (b -> a -> b) -> b -> [a] -> [b] |
// scanl :: (b -> a -> b) -> b -> [a] -> [b] |
||
const scanl = |
const scanl = f => startValue => xs => |
||
xs.reduce((a, x) => { |
|||
const v = f(a[0])(x); |
|||
return Tuple(v)(a[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] |
// scanl1 :: (a -> a -> a) -> [a] -> [a] |
||
const scanl1 = |
const scanl1 = f => |
||
// scanl1 is a variant of scanl that has no |
|||
// starting value argument. |
|||
xs => xs.length > 0 ? ( |
|||
scanl(f)( |
|||
xs[0] |
|||
)(xs.slice(1)) |
|||
) : []; |
|||
// scanr :: (b -> a -> b) -> b -> [a] -> [b] |
// scanr :: (b -> a -> b) -> b -> [a] -> [b] |
||
const scanr = |
const scanr = f => |
||
startValue => xs => xs.reduceRight((a, x) => { |
|||
const v = f(x)(a[0]); |
|||
return Tuple(v)([v].concat(a[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] |
// scanr1 :: (a -> a -> a) -> [a] -> [a] |
||
const scanr1 = |
const scanr1 = f => |
||
// scanr1 is a variant of scanr that 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); |
|||
// |
// subtract :: Num -> Num -> Num |
||
const |
const subtract = x => |
||
y => y - x; |
|||
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); |
|||
// |
// sum :: [Num] -> 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> |
})();</lang> |
||
{{Out}} |
{{Out}} |