0

I want to filter the items array objects which match the "model" key in the models array and store them in an array. I did succeed in my attempt but I am not very satisfied with my effort. Are there any better ways of doing it?

Any suggestions on how to do it using underscore.js and lodash? Or using the native javascript map and filter functions?

The JSON object

 {
"items": [
  {
    "model": "ooc0d",
    "code": "2x4qr",
    "price": 33
  },
  {
    "model": "ruie9",
    "code": "2f6gi",
    "price": 22
   },
  {
    "model": "aqu0d",
    "code": "2f6gi",
    "price": 21
  },
  {
    "model": "ddebd",
    "code": "2f6gi",
    "price": 25
  },
  {
    "model": "ddebd",
    "code": "2f6gi",
    "price": 29
  }
],
"models": [
  {
    "model": "ruie9",
    "year": 1998
  },
  {
    "model": "ooc0d",
    "year": 1991
  },
  {
    "model": "aqu0d",
    "year": 1994
  },
  {
    "model": "ddebd",
    "year": 1995
  },
  {
    "model": "odq76",
    "year": 1999
  }
]
}

My Solution

const { models, items } = jsonData;

const newarray = [];

for(let i = 0; i < models.length; i++) {
   for(let j = 0; j < items.length; j++) {
     if(items[j].model===models[i].model) {

       let obj = {
         ...items[j],
         year: models[i].year
       }
       newarray.push(obj);
    }
   }
 }
3
  • 1
    in your code you access the id property but there is not track of id property in your JSON Commented May 31, 2017 at 22:23
  • Oops I am sorry. Just corrected Commented May 31, 2017 at 22:28
  • @created this benchmark with me Umair and Pankaj. Pankaj wins :) Commented May 31, 2017 at 23:06

4 Answers 4

3

I would take a slightly different approach. I guess you might like it.

 const models = [
      {
        "model": "ruie9",
        "year": 1998
      },
      {
        "model": "not-found",
        "year": 1991
      },
      {
        "model": "aqu0d",
        "year": 1994
      },
      {
        "model": "ddebd",
        "year": 1995
      },
      {
        "model": "odq76",
        "year": 1999
      }
    ];
    
    const items = [
      {
        "model": "ooc0d",
        "code": "2x4qr",
        "price": 33
      },
      {
        "model": "ruie9",
        "code": "2f6gi",
        "price": 22
       },
      {
        "model": "aqu0d",
        "code": "2f6gi",
        "price": 21
      },
      {
        "model": "ddebd",
        "code": "2f6gi",
        "price": 25
      },
      {
        "model": "ddebd",
        "code": "2f6gi",
        "price": 29
      }
    ];
    
    
    
    const transformed = models.reduce((res, val) => {
      res[val.model] = val;
      
      return res;
    }, {}); // Transform models into a dictionary.
    
    
    const filtered = items.filter(i => i.model in transformed);
    
    console.log(filtered);

Sign up to request clarification or add additional context in comments.

3 Comments

@1033 Glad I could help.
Also, by using this approach you just have to loop through the models list once instead of looping through it on every iteration.
@KarenGrigoryan Well that's interesting :)
2

You could do this:

I thought you wanted to add the year from models array too. If so, look at this implementation. This is more efficient O(n) than O(n*n) solution that you attempted earlier. For large arrays O(n*n) is not preferred.

let items = [{
    "model": "ooc0d",
    "code": "2x4qr",
    "price": 33
  },
  {
    "model": "ruie9",
    "code": "2f6gi",
    "price": 22
  },
  {
    "model": "aqu0d",
    "code": "2f6gi",
    "price": 21
  },
  {
    "model": "ddebd",
    "code": "2f6gi",
    "price": 25
  },
  {
    "model": "ddebd",
    "code": "2f6gi",
    "price": 29
  }
];

let models = [
  {
    "model": "ruie9",
    "year": 1998
  },
  {
    "model": "ooc0d",
    "year": 1991
  },
  {
    "model": "aqu0d",
    "year": 1994
  }
];

let objModels = models.reduce(function(r,v) {
 r[v.model] = v;
 return r;
}, {});

let objItems = items.reduce(function(r,v) {
 r[v.model] = v;
 return r;
}, {});

let ans = [];
for(let key in objItems) {
   if(key in objModels) {
   let o = objItems[key];
   o.year = objModels[key].year;
    ans.push(o);
    
   }
}

console.log(ans);

3 Comments

Great! Can you explain how my solution complexity is O(n*n)?
@Umair When did I say yours was O(n*n)? It was for OP. However, yours is not even the solution that OP was looking for. He wanted year to be attached too. Look at OP's attempted solution for line year: models[i].year.
@KarenGrigoryan Thanks! Thanks for setting up the fiddle too!
1

You can rewrite

let obj = {
  ...items[j],
  year: models[i].year
}

as

let obj = Object.assign({}, items[j], { year: models[i].year });

And you can also use Array.prototype.forEach instead of a for loop, like so

models.forEach((m) => {
  items.forEach((i) => {
    if (m.id === i.id) {
      let obj = Object.assign({}, i, { year: m.year });

      newArray.push(obj);
    } 
  })
})

I tried to keep it as similar to your solution as possible.

Comments

1

Try this snippet:

const jsonData = {
  "items": [{
      "model": "ooc0d",
      "code": "2x4qr",
      "price": 33
    },
    {
      "model": "ruie9",
      "code": "2f6gi",
      "price": 22
    },
    {
      "model": "aqu0d",
      "code": "2f6gi",
      "price": 21
    },
    {
      "model": "ddebd",
      "code": "2f6gi",
      "price": 25
    },
    {
      "model": "ddebd",
      "code": "2f6gi",
      "price": 29
    }
  ],
  "models": [{
      "model": "ruie9",
      "year": 1998
    },
    {
      "model": "ooc0d",
      "year": 1991
    },
    {
      "model": "aqu0d",
      "year": 1994
    },
    {
      "model": "ddebd",
      "year": 1995
    },
    {
      "model": "odq76",
      "year": 1999
    }
  ]
};

var newArray = jsonData.models.reduce(
  (acc, modelData) => {
    let filteredItems = jsonData.items.filter(item => item.model === modelData.model);
    if (filteredItems.length) {
      acc.push(...filteredItems);
    }
    return acc;
  }, [])

console.log(newArray);

5 Comments

Thanks man :) May I know what does the [ ] do in the end of the reduce function?
Well this is a much cleaner solution, but you are running filter on each iteration which IMO is exhaustive.
@1033 always welcome. [] is the initial value of acc, it's optional if you omit it, then the first value of acc will be the first element of jsonData.models.
@Umair interesting, but I intentionally use filter because every model has 1 to many relationship with items, so every model can have several items linked to it, that's why I filter those items on every model. If you have better suggestion please feel free to edit or add your variant.
@KarenGrigoryan I totally understand your use of filter and I am not saying its wrong. Please check my answer with my preferred approach and please share your thoughts too.

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.