0

I'm working with mockData for a web app and I'm trying to loop over nested objects. My problem is that a for loop works but not array.map and don't know why.

Here is the for loop:

  for (let i = 0; i < fakeChartData.length; i++) {
    for (let j = 0; j < fakeChartData[i].poll.length; j++) {
      if (fakeChartData[i].poll[j].id === id) {
        return fakeChartData[i].poll[j]
      }
    }
  }

And here is the map loop:

  fakeChartData.map(data => {
    data.poll.map(data => {
      if (data.id === id) {
        return data;
      }
    });
  });

My Data structure:

fakeChartData = [
  {
    id: '232fsd23rw3sdf23r',
    title: 'blabla',
    poll: [{}, {}]
  },
  {
    id: '23dgsdfg3433sdf23r',
    title: 'againBla',
    poll: [{}, {}]
  }
];

I'm trying to load the specific object with the id passed to it on onClick method. Here is the full function:

export const fetchPollOptById = (id) =>
  delay(500).then(() => {
    for (let i = 0; i < fakeChartData.length; i++) {
      for (let j = 0; j < fakeChartData[i].poll.length; j++) {
        if (fakeChartData[i].poll[j].id === id) {
          return fakeChartData[i].poll[j]
        }
      }
    }
});
15
  • you should provide an example of data structure... Commented Jun 30, 2016 at 10:21
  • How is this run? We have problems with using array.map in our tests. They are run using jasmine and phantom.js. Phantom.js seems to be missing support for array.map Commented Jun 30, 2016 at 10:22
  • 1
    Consider what the return statement inside the map is returning from. Commented Jun 30, 2016 at 10:23
  • The if statement make me think you mix up .map() with .filter(). map should always return a value while filter is for returning an array that only contain the elements that meet your criterion Commented Jun 30, 2016 at 10:25
  • 1
    map does something completely different. Why did you want to use it in the first place? "I did try to use .filter() but it seemed to return the original data rather than the computed one" Just like your code. What's your point? Commented Jun 30, 2016 at 11:08

4 Answers 4

3

A return statement inside a for loop causes your function to return. However, a return statement inside a .map() function's callback only returns the callback and this returned value is then placed in the new array. Please see the documentation.If you really want to be using .map(), you could do it like this:

export const fetchPollOptById = (id) => {
    var result;
    fakeChartData.map(data => {
        data.poll.map(data => {
            if (data.id === id) {
                result = data;
                return data;
            }
        });
    });
    return result;
}

note: I also assume that your poll objects have an id field like this:

  fakeChartData = [
      {
          id: '232fsd23rw3sdf23r',
          title: 'blabla',
          poll: [
              {id: 'pollId1', otherField: 'blah'},
              {id: 'pollId2', otherField: 'blah'}
          ]
      },
      {
          id: '23dgsdfg3433sdf23r',
          title: 'againBla',
          poll: [
              {id: 'pollId3', otherField: 'blah'},
              {id: 'pollId4', otherField: 'blah'}
          ]
      }
  ];

You can then get the poll data like this:

fetchPollOptById("pollId3"); //returns {id: "pollId3", otherField: "blah"}
Sign up to request clarification or add additional context in comments.

2 Comments

I got it now mate but thanks anyways. Though, your answer is close to what I want but I already accepted someone else's answer but If I could do it again, then it would be your answer. Cheers
You have the option to change the accepted answer as you are the author of the question, but only do it if you see my answer as more helpful to you. See meta.stackexchange.com/questions/93969/…
2

If I'm right about what you're trying to do, this should work:

return fakeChartData.reduce((acc, data) => acc.concat(data.poll), [])
                    .filter(pollObj => pollObj.id === id)[0]

First it makes an array containing all the poll objects from different data objects, then it filters them to find the one with the correct id and returns that object.

As to why your approach using map does not work: you are using it in the wrong way. What map does it to take a function and apply it to every member of an array.

Here's an array and function kind of like yours:

const arr = [1,2,3]
const getThingById(id) => {
  var mappedArray = arr.map(x => {
    if(x === id) return x
  })
  console.log(mappedArray) // [3]
}
getThingById(3) // undefined

This won't work. getThingById has no return statement. The return statement return x is returning something from the function that is passed into map. Basically, you shouldn't be using map to do what you're trying to do. map is for when you want to return an array.

6 Comments

This works but I was looking into why wasn't the .map() not working. I've already got the example to work with plain for-loops.
Your example with map does not work, because the return statement only exits the second callback. Both callbacks will still iterate the whole arrays. The array you will get as a result from your example will only contain undefined. map
@R.Schmitt Thanks for the explanation. The others just gave me their solution with nothing as to "because". Thanks
@otajor I will accept your answer is it is the shortest and also immutable.
Cheers for accepting - I just edited with some more explanation about why map doesn't work. I would suggest you do some more reading about map, filter, reduce and forEach and figure out when you should use each one.
|
1

Try this

fakeChartData.map(data => {
    var result = data.poll.map(data => {
      if (data.id === id) {
        return data;
      }
    });
    return result;
  });

It should work. And yeah you should use find() instead of map() I think.

1 Comment

.find is not supported by IE
1

A bit long implementation:

let results = fakeChartData.map(data => {
    let innerResult = data.poll.filter(data => {
      if (data.id === id) {
        return data;
      }
     return innerResult.length ? innerResult[0] : null;
    });
  })
  .filter(x => (x !== null));
let whatYouwant = results.lenght ? results[0] : null;

If you can use find() it would look nicer, but that depends on what browsers you need to support

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.