FAQ: Iterators - Review

This community-built FAQ covers the “Review” exercise from the lesson “Iterators”.

Paths and Courses
This exercise can be found in the following Codecademy content:

Web Development

Introduction To JavaScript

FAQs on the exercise Review

There are currently no frequently asked questions associated with this exercise – that’s where you come in! You can contribute to this section by offering your own questions, answers, or clarifications on this exercise. Ask or answer a question by clicking reply (reply) below.

If you’ve had an “aha” moment about the concepts, formatting, syntax, or anything else with this exercise, consider sharing those insights! Teaching others and answering their questions is one of the best ways to learn and stay sharp.

Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply (reply) below!

Agree with a comment or answer? Like (like) to up-vote the contribution!

Need broader help or resources? Head here.

Looking for motivation to keep learning? Join our wider discussions.

Learn more about how to use this guide.

Found a bug? Report it!

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!

I was looking at the challenges after the exercise and there was one that involved multi-layered arrays. I assume that is the same as a multi-dimensional array? So in other words, arrays would be elements within an array, e.g. :

const arr = [ [1,2,3], [4,5,6], [7,8,9] };

const myArray = [‘Albany’,‘britain’,‘dubai’,‘ukraine’,‘luxembourg’]

const myName = myArray.reduce((acc, currVal) => {
return acc[0] + currVal[0]
});

console.log(myName)

This code is supposed to return “Abdul”, but returns “Albanybdul”. What’s wrong???

Look at the result you got, where did the lettters come from? That says a whole lot about what reduce did.
You can also (and should) read the documentation for reduce, so that you know what its behaviour is.
You can add prints in your code to get information out as it runs.

Plenty of ways to get more information!

I solved the “transform a multi-layered array into a single-layer array using .reduce()” exercise like this:

const multiArray = [ [1,2,3], [4,5,6]];
let newArray=[];
multiArray.forEach( singleArray => {
  newArray.push(singleArray.reduce((accu, currVal) => { return accu + currVal}));
});
console.log(newArray);

I wonder if that’s what was meant by the instructions, though. :face_with_monocle:

I do believe they want the result of that to be:

[1, 2, 3, 4, 5, 6]

You’re reducing each subarray with addition (reduce with + is equivalent to sum)
Perhaps you should be reducing the whole array instead?

reduce isn’t entirely appropriate for flattening an array though, because repeated concatenation is inefficient, and it’ll only get rid of one layer! But for small inputs and only getting rid of one layer, sure.

I’d be really tempted to write it like this instead:

const add = (a, b) => a + b
singleArray.reduce(add)

I’d also want to use map instead of forEach, though, that’s for what your current code is doing, not what they’re asking for.

// same as your code

const add = (a, b) => a + b
const multiArray = [[1,2,3], [4,5,6]]
const newArray = multiArray.map(subArr => subArr.reduce(add))
console.log(newArray)

Or, since we established reducing with + is equivalent to sum, why not define sum:

// same as your code

const add = (a, b) => a + b
const sum = arr => arr.reduce(add)
const multiArray = [[1,2,3], [4,5,6]]
const newArray = multiArray.map(sum)
console.log(newArray)
4 Likes

I think you’re right! Thanks!
I found another solution to these instructions in the documentation of the reduce() function (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Flatten_an_array_of_arrays). It would look like this for our example:

const multiArray = [ [1,2,3], [4,5,6]];
let newArray = multiArray.reduce( (accu, currVal) => {
    return accu.concat(currVal);
  },
  []
);
console.log(newArray);
1 Like

Not necessarily better, but I’d like to highlight that the reducer is concat:

const multiArray = [[1,2,3], [4,5,6]]
const concat = (a, b) => a.concat(b)
let newArray = multiArray.reduce(concat, [])
console.log(newArray)

I even wanted to send in Array.prototype.concat without defining concat, but it turns out that it has optional arguments which will get some strange things from reduce which sends 4 arguments rather than 2

In some languages concat is the same as +
but errrr. javascript… sigh.

[] + [1]  // '1'

Oh and the REAL solution here is to send all the subarrays to concat directly. Because that won’t concat multiple times, it’ll do it all in one go.

// much better:
const multiArray = [[1,2,3], [4,5,6]]
let newArray = Array.prototype.concat(...multiArray)
console.log(newArray)
1 Like

Totally true, .concat() does the reduction and actually .reduce() is not strictly necessary. But I think the solution is supposed to outline two things taught in this lesson:

  1. How to make use of the way .reduce() separates array elements into individual variables, and
  2. read the documentation and you will find easy solutions. :wink:

Reduce makes it worse, catastrophically so.
Which is why I have to point out that this particular situation is bad.
Concatting these one at a time:

abcdefghijk

Results in ALL these being created:

a
ab
abc
abcd
abcde
abcdef
abcdefg
abcdefgh
abcdefghi
abcdefghij
abcdefghijk

Only the last one should get created. So the total work with reduce and concat is n*n/2, but it should only be the last one which is n long

Obviously the current characters should be reused to fix the problem, instead of copying them every iteration.

With 1000 elements this is 500000 amount of work instead of 1000. That’s still not so bad even though it’s an unreasonable amount of work. With 1000000 elements, that program suddenly becomes completely unresponsive for hours for something that should have taken a couple of milliseconds.

This isn’t reduce’s fault at all. But reduce with concat is probably not the right thing to do.

For anything we write we need to know what they do, and consider if it’s reasonable. This doesn’t usually involve digging very far down, but rather, concat takes time relative to the amount of elements involved, and reduce does one iteration per element (in this case: multiply them together to get the amount of time required)

1 Like

Hey thank you for sharing Nikah! I’m not sure exactly what is being asked by the instructions either. :-/

Hey, how do you define callback function before iteration if could some one give me an example?

1 Like
let num = [1,2,3,4];
let sum = 0;
const bigNums = num.map(add =>{
  return add*5;
});
function add(){
  for(let i=0;i<num.length;i++){
    sum = sum + num[i];
  }
  return sum;
}
console.log(add());
console.log(bigNums);

nums=[[1,2],[3,4],[5,6]];
const flat = nums.reduce((total, amount) => {
  return total.concat(amount);
}, []);
console.log(flat);

This is the solution of this excercise

I know that multi-layered array challenge asks for using .reduce in order to get a single layered array (to get rid of inner brackets).
But what if I wanted to sum all arrays’ items that have the same index?
Example:
nArrays = [[1, 2], [3, 4], [5, 6], [7, 8]];

I want to sum all items that have index 0 (that means 1 + 3 + 5 + 7) and
all items with index 1 (2 + 4 + 6 + 8). Output: [16, 20];
Should I use .reduce in this case or is there any better solution?

I found the solution at Stack Overflow
https://stackoverflow.com/questions/56178760/sum-of-nested-arrays-according-to-their-index

const total = nArrays.reduce((a, b) => a.map((c, i) => c + b[i]));

1 Like

If you have a transpose function (turns columns into rows) available then you could transpose and then map sum
haskell:

ghci> nArrays = [[1, 2], [3, 4], [5, 6], [7, 8]] :: [[Int]]
ghci> nArrays & transpose & map sum
[16,20]

…plenty of ways to express it I guess, whatever makes sense to you.

python:

>>> nArrays = [[1, 2], [3, 4], [5, 6], [7, 8]]
>>> list(map(sum, zip(*nArrays)))
[16, 20]
>>> [sum(col) for col in zip(*nArrays)]
[16, 20]

hmm lodash has zip and sum, so, that translates into:

javascript:

> const _ = require('lodash')
> const nArrays = [[1, 2], [3, 4], [5, 6], [7, 8]]
> _.zip(...nArrays).map(_.sum)
[ 16, 20 ]
1 Like

As a newbie at this, I only got a few of your explanation, as well as I’m still trying to understand how the solution found at Stack Overflow works.
Anyway, I want to thank you for your time and information about my question!

The SO one is really nested, probably best to think of it as some one-liner that isn’t meant to be read and probably not be used either unless you fluently wrote it yourself.

The function inside that reduce is element-wise add. And what reduce does is to place that function between every element in the list.

[[1, 2],
(element-wise add)
 [3, 4],
(element-wise add)
 [5, 6],
(element-wise add)
 [7, 8]]

And then evaluate starting from the top. Or if you supply an inital accumulator value:

acc
(element-wise add)
[[1, 2],
(element-wise add)
 [3, 4],
(element-wise add)
 [5, 6],
(element-wise add)
 [7, 8]]

So if reduce by itself makes sense, and if element-wise by itself makes sense, then they can start making sense together too. I think they need to be looked at separately to make sense out of them, not everything at once.

One way to look at reduce is like above: place the function between each element.
Another is to think of it as just a loop. It applies a loop body (the function) to each element. (and starts out with some initial value, possibly the first element from the list)

Here’s how I’d rather write it:

// original:
// const total = nArrays.reduce((a, b) => a.map((c, i) => c + b[i]));

// split it up into functions that make sense on their own,
// that doesn't make you tie your brains into seven knots to understand
const elemWiseAdd = (a, b) => a.map((_, i) => a[i] + b[i])
const colWiseSum = arr => reduce(elemWiseAdd, arr)
const total = colWiseSum(nArrays)

btw, SUM can be implemented as REDUCE(ADD, VALUES), which is also exactly what the above says (and, indeed, sum is something you compute by putting (+) between each value)

1 Like

Which translates to the pit lane of an F1 track where the speed limit is 75 mph. One suspects we need to bump things down to go-kart speed, where the pit lane speed limit is 5 mph.

One might mistakenly presume that by this stage (iterators) much of the core mechanics would be understood; that is, presume, followed by the wont to explore the depths given a wider field of view. In this instance, given we are asked to reverse engineer a solution gleaned from the web, I’m more inclined to go with the ‘fluently wrote yourself’ statement quoted above and not disseminate that solution. It would be in your interest to do so, however. That you will not forget once every piece falls into place.

1 Like

Thanks for your advice.

1 Like