Reputation: 1951
I want to add a new object between each object in an array using functional programming. The new object is derived using its two neighbors.
Let’s say that we start with an array of integers [1,2,3]
, I want to add new integers by adding its neighbors so the resulting array looks like this [1,3,2,5,3]
I know of intersperse but that only allows me to add a static element. I also considered chain but that only visits one element at a time
Upvotes: 0
Views: 54
Reputation: 193057
You can use R.mapAccum
to create an array that uses the previous item (saved in the accumulator). Take the result of R.mapAccum
, and use R.last
to get the array (dropping the accumulator), flatten, and remove the redundant first item:
const { pipe, mapAccum, last, flatten, tail } = R
const fn = pipe(
mapAccum((a, b) => [b, [a + b, b]], 0),
last, // take the array of pairs (drop the accumulator)
flatten, // flatten the array of pairs to an array of numbers
tail // take all items after the redundant first
)
const numbers = [1, 2, 3]
const result = fn(numbers)
console.log(result) // [1,3,2,5,3]
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js" integrity="sha512-t0vPcE8ynwIFovsylwUuLPIbdhDj6fav2prN9fEu/VYBupsmrmk9x43Hvnt+Mgn2h5YPSJOk7PMo9zIeGedD1A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Vanilla JS - reduce the array to another array. On each iteration, spread the previous accumulator (acc
), create an item by adding the current number to the previous number on the accumulator (or 0 if none), and also include the current number. Slice redundant first element off.
const fn = (cb, arr) => arr.reduce((acc, n) =>
[...acc, cb(n, acc.at(-1) ?? 0), n]
, []).slice(1)
const numbers = [1, 2, 3]
const add = (a, b) => a + b
const result = fn(add, numbers)
console.log(result) // [1,3,2,5,3]
Upvotes: 2
Reputation: 50807
I played around with some Ramda versions, including one similar to Ori Drori's answer and one that used aperture
(2)
, but nothing was as compelling as this vanilla JS version:
const between = (fn) => (xs) =>
xs .flatMap ((x, i, a) => i == 0 ? [x] : [fn (a [i - 1], x), x])
const add = (a, b) => a + b
console .log (between (add) ([1, 2, 3]))
We could replace fn (a [i - 1], x)
with fn (a [i - 1], x, i, a)
if your needs extended beyond working with the two neighbors. Although at that point, I would probably be looking toward scan
or mapAccum
.
While we could start toward point-free with a version like this:
const between = (fn) =>
addIndex (chain) ((x, i, a) => i == 0 ? [x] : [fn (a [i - 1], x), x])
getting entirely point-free look difficult and likely to obfuscate more than it clarifies. I wouldn't bother.
Upvotes: 1