1

Array#map, Array#filter create a new array and hence effectively iterating over the array (or creating new array).

Whereas in rust, python, java, c#, etc. such expression chain will iterate only once.

In most cases this is irrelevant and we do not have to care about that. However in some cases the performance hit could be a deal breaker to leverage the function api of the Array class.

How do you mitigate this? So you have any preference on a library enabling lazy evaluation for functional expression?

Nas
  • 1,063
  • 2
  • 9
  • 22
  • 3
    Write it out as a loop, or use [iterator methods](https://github.com/tc39/proposal-iterator-helpers). – Bergi May 17 '21 at 15:50
  • What if `reduce` is chained further with a `map`? How can that in general work without first performing the whole iteration needed to perform the reduction? – trincot May 17 '21 at 16:55
  • Duplicate of https://stackoverflow.com/questions/57042520/equivalent-of-scala-view-in-javascript/57043367 – loop Oct 14 '21 at 20:25
  • https://www.npmjs.com/package/stream-list does exactly this. `npm i stream-list` – ohrlando Aug 16 '23 at 18:45

4 Answers4

1

If you don't want it to iterate more than once. You can use a loop

const numbers = [1,2,3,4,5,6]
let result = 0;
for(const number of numbers) {
  const square = number * number
  if(square % 2) {
    result += square
  }
}
console.log(result)

Or reduce

const numbers = [1,2,3,4,5,6]
const result = numbers.reduce((acc, number) => {
  const square = number * number
  if(square % 2) {
    return acc + square
  }
  return acc
}, 0)
console.log(result)

Array methods aren't functional so the whole premise is flawed. The fact that they exist on the array object means they aren't open composition the way pure functions are. You can get closer though

const square = (n) => n * n
const oddNumberOrZero = (n) => n % 2 ? n : 0
const add = (a, b) => a + b
const addOddSquare = (a, b) => add(a, oddNumberOrZero(square(b)))
const reduce = (arr, fn, acc) => arr.reduce(fn,acc)
const numbers = [1,2,3,4,5,6]

const result = reduce(numbers, addOddSquare, 0)

console.log(result)

You also seem to be conflating fluent interfaces with functional programming.

Andrew Gillis
  • 3,250
  • 2
  • 13
  • 15
  • Well array methods aren't strictly functional. They are just methods on the Array prototype which is by all measures object oriented. – Andrew Gillis May 17 '21 at 16:06
1

I believe what you are looking for is processing the array as a stream. You can do that with highland:

import _ from "highland";
_([1, 2, 3, 4])
    .filter(v => v % 2 === 0)
    .map(v => v * 2)
    .toArray((result: number[]) => {
        // result is the new array
    });

Relevant part from the docs:

Arrays - Streams created from Arrays will emit each value of the Array (...)

F. Gouveia
  • 183
  • 6
0

You can install stream-list lib from npm

https://www.npmjs.com/package/stream-list

let myNumbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 let mylist = new List(myNumbers);
 myList
  .filter((num) => num % 2 == 0)  //only pair
  .map((num) => num * num)  // square
  .map((num) => num/2) // half
  .toList(); // myNumbers was just itered once
ohrlando
  • 106
  • 11
-1

Please check the following code lines. In the code, in which v * v is divided 2 means that v is divided.

const numbers = [1,2,3,4,5,6];
const res = numbers.reduce((sum, v)=> sum + (v % 2? v * v: 0), 0);
console.log(res)
Reinis
  • 477
  • 1
  • 5
  • 13