Functional programming on nested arrays

Viewed 557

I'm trying to do more and more functional programming instead of imperative programming.

Let's say I have a nested array data structure and I want to change the values of the deeper inner array, what would be the best way to do it?

Imperative code to transform:

for (let i = 0; i < dataSheet.length; i++) {
    for (let j = 0; j < dataSheet[i].questions.length; j++) {
        for (let k = 0; k < dataSheet[i].questions[j].answers.length; k++) {
            dataSheet[i].questions[j].answers[k].name += ' (edited name)';
            dataSheet[i].questions[j].answers[k].value = 1 + dataSheet[i].questions[j].answers[k].value / 10;
        }
    }
}

I came up with two ways of doing it:

With map():

dataSheet
.map(section => section.questions
    .map(question => question.answers
        .map(answer => (
            {
                ...answer,
                name: answer.name + ' (edited name)',
                value: 1 + (answer.y / 10),
            }),
        ),
    ),
);

With forEach():

dataSheet.forEach(section => section.questions
    .forEach(question => question.answers
        .forEach(answer => (
            {
                ...answer,
                name: answer.name + ' (edited name)',
                value: 1 + (answer.y / 10),
            }),
        ),
    ),
);

All 3 do the same things, but none of them really look better. It does not look better, especially because of the pyramid of doom... And it could be even worse if I had deeper nested arrays.

Going from imperative to functional does not make the code much clearer/readable/maintainable in this case and it is probably slower since it will create a new copy for every object modified.

Hence, in this scenario, do you think it will be better to keep the code in a imperative way? Or is there better way to do it?

1 Answers

Going from imperative to functional does not make the code much clearer/readable/maintainable in this case and it is probably slower since it will create a new copy for every object modified.

I would argue that

.map(answer => [code block])

is more readable than

for (let k = 0; k < dataSheet[i].questions[j].answers.length; k++) [code block]

Although you do not get to eliminate nesting with your map example you get a lot of benefits that make your code more maintainable.

  • You do not get to mess with the i,j,k.. variables and introduce bugs.
  • You get purity and that is "the" big reason to do functional programming. The map may be slower for this simple case but with this way you allow your input to be immutable and be used/stored elsewhere while preserving integrity.

(forEach would not work because it doesn't return anything)

I would suggest you use the functional way, since you do not get any advantages with the imperative one except for a trivial amount of performance.

Related