最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Javascript map over array of obj with another array to get different key value - Stack Overflow

programmeradmin6浏览0评论

So I am not sure why I having such a difficult time with this, but I have an array of ids that I am trying to use to map over an array of objects to find the corresponding id but return the value from a different key.

i.e.: arr=[13, 1, 16]

arrObj= [{
          id: 1,
          name: "cat"
         }, {
          id: 10,
          name: "tiger", 
         }, {
          id: 3,
          name: "dog", 
         }, {
          id: 16,
          name: "bear", 
         }, {
          id: 8,
          name: "fish", 
         }, {
          id: 13,
          name: "goat", 
         }]

and I want it to return: ["goat", "cat", "bear"]

I have a nested map function that does this but returns undefined for the objects that do not have a corresponding ID. I could filter out the undefineds from the returned array, but it seems that there is a cleaner/more efficient way to do this.

What is the cleanest way to achieve this?

So I am not sure why I having such a difficult time with this, but I have an array of ids that I am trying to use to map over an array of objects to find the corresponding id but return the value from a different key.

i.e.: arr=[13, 1, 16]

arrObj= [{
          id: 1,
          name: "cat"
         }, {
          id: 10,
          name: "tiger", 
         }, {
          id: 3,
          name: "dog", 
         }, {
          id: 16,
          name: "bear", 
         }, {
          id: 8,
          name: "fish", 
         }, {
          id: 13,
          name: "goat", 
         }]

and I want it to return: ["goat", "cat", "bear"]

I have a nested map function that does this but returns undefined for the objects that do not have a corresponding ID. I could filter out the undefineds from the returned array, but it seems that there is a cleaner/more efficient way to do this.

What is the cleanest way to achieve this?

Share Improve this question asked Jun 22, 2018 at 18:54 CharStarCharStar 4271 gold badge6 silver badges25 bronze badges
Add a ment  | 

5 Answers 5

Reset to default 6

You could use Array#map and search with Array#find for the corresponding object. Then take name as return value.

var arr = [13, 1, 16],
    arrObj = [{ id: 1, name: "cat" }, { id: 10, name: "tiger" }, { id: 3, name: "dog" }, { id: 16, name: "bear" }, { id: 8, name: "fish" }, { id: 13, name: "goat" }],
    result = arr.map(id => arrObj.find(o => o.id === id).name);

console.log(result);

For a lots of data, you could take a Map and build it by mapping key value pairs and then map the result of the map.

var arr = [13, 1, 16],
    arrObj = [{ id: 1, name: "cat" }, { id: 10, name: "tiger" }, { id: 3, name: "dog" }, { id: 16, name: "bear" }, { id: 8, name: "fish" }, { id: 13, name: "goat" }],
    result = arr.map(
        Map.prototype.get,
        new Map(arrObj.map(({ id, name }) => [id, name]))
    );

console.log(result);

Try this:

var arr=[13, 1, 16];
var arrObj= [{
          id: 1,
          name: "cat"
         }, {
          id: 10,
          name: "tiger", 
         }, {
          id: 3,
          name: "dog", 
         }, {
          id: 16,
          name: "bear", 
         }, {
          id: 8,
          name: "fish", 
         }, {
          id: 13,
          name: "goat", 
         }];

var result = arr.map(id => arrObj.find(x => x.id == id)).map(x => x.name)
console.log(result);
// ["goat", "cat", "bear"]

.map() (from MDN web docs):

method creates a new array with the results of calling a provided function on every element in the calling array.

.find() (from MDN web docs):

method returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.

There have been a lot of good answers already, however i feel the need to push for newer syntax as it is greater to work with in the long run.

const getNamesBasedOnIds = (arr, listOfIds) => {
   return arr.reduce(((sum, element) => 
      [...sum, ...(listOfIds.includes(element.id) ? [element.name] : [])]),
   []);
}

const animals = getNamesBasedOnIds(arrObj, [13,1,16]);

Using Array.filter, then Array.map requires you to run through the Array max twice.

With Array.reduce you can add elements to the sum if they exists in listOfIds, then after running through the arrObj once you have the result

[...sum, ...(listOfIds.includes(element.id) ? [element.name] : [])] is pretty slow, but its more for showing the use of spear operators

The above is equivalent to

sum.concat(listOfIds.includes(element.id) ? element.name : [])]

The fastest way, is to use Array.push

if(listOfIds.includes(element.id)){
   sum.push(element.name);
}
return sum;

The correct way is to not nest any loops:

  1. reduce your array of objects to a map of 'id-values' idValueMap
  2. map through your array of 'ids' idArr using the idValueMap to get the corresponding values for each id in constant time.

Thought Process

Understand that the biggest problem is the data itself. Don't let insufficient data types or structures force you you have a bad solution/code. Transform the data such to what you need so that you can create a proper solution.

Basically imagine if the objArr was just a Map that you could use to look up the values for an id.... then the solution is straight forward. So let's make that happen and then the rest falls into place. Data Data Data is what I always say :)

Rule of thumb NEVER run a loop inside of a loop if you can help it. FYI: filter, find, map, indexOf .... are all loops internally, do not nest them unless you absolutely must.

This solution is by far the most performant. This way you are not running O(n^2) (very BAD), you are instead running O(n) (very GOOD):

    const idArr = [ 13, 1, 16 ];
    const objArr= [
      {
        id: 1,
        name: "cat"
      }, 
      {
        id: 10,
        name: "tiger", 
      }, 
      {
        id: 3,
        name: "dog", 
      }, 
      {
        id: 16,
        name: "bear", 
      }, 
      {
        id: 8,
        name: "fish", 
      }, 
      {
        id: 13,
        name: "goat", 
      }
    ];
    
    const idValueMap = objArr.reduce((acc, { id, name }) => ({ ...acc, [id]: name }), {});
    let output = idArr.map((id) => idValueMap[id]);
    console.log(output);

You can first use .filter to filter and then use .map to output the desired properties

here

var arr = [13, 1, 16],
    arrObj = [{
        id: 1,
        name: "cat"
    }, {
        id: 10,
        name: "tiger",
    }, {
        id: 3,
        name: "dog",
    }, {
        id: 16,
        name: "bear",
    }, {
        id: 8,
        name: "fish",
    }, {
        id: 13,
        name: "goat",
    }];

var res = arrObj.filter(o => arr.indexOf(o.id) >= 0);

console.log(res.map(o => o['name']))

发布评论

评论列表(0)

  1. 暂无评论