1

I'm struggling with something that seems like it should be trivial. I have an array of objects:

const vehicles = [
{
    "sku": "1234",
    "year": "2004",
    "make": "Chevrolet",
    "model": "Avalanche",
},
{
    "sku": "1234",
    "year": "2006",
    "make": "Chevrolet",
    "model": "Avalanche",
},
{
    "sku": "1234",
    "year": "2009",
    "make": "Chevrolet",
    "model": "Silverado 1500",
},
{
    "sku": "1234",
    "year": "2006",
    "make": "Chevrolet",
    "model": "Silverado 1500",
}]

I would like to match on sku, make, and model and flatten the objects to have a final state of:

const mutatedVehicles = [
  {
    "sku": "1234",
    "years": ["2004", "2006"],
    "make": "Chevrolet",
    "model": "Avalanche",
  },
  {
    "sku": "1234",
    "years": ["2009", "2006"],
    "make": "Chevrolet",
    "model": "Silverado 1500"
  }]

I've actually worked with this in Python initially using dictionaries, but ultimately prefer some of the methods available in JS. I've tried using Array.forEach, Object.assign, and a few other methods and have come up short.

EDIT: I was asked to share some of the code I had tried - it's Python, not JS, as that's where I initially started.

def match_props(f, x):
    if f['sku'] == x['sku'] and f['year'] != x['year'] and f['make'] == x['make'] and f['model'] == x['model']:
        return True
    else:
        return False

fitments = [
    {
        "sku": "1234",
        "year": "2004",
        "make": "Chevrolet",
        "model": "Avalanche",
        "drive": "",
    },
    {
        "sku": "1234",
        "year": "2009",
        "make": "Chevrolet",
        "model": "Silverado 1500",
        "drive": "",
    },
    {
        "sku": "1234",
        "year": "2006",
        "make": "Chevrolet",
        "model": "Silverado 1500",
        "drive": "",
    },
]

merged = []

for f1 in fitments:
    pMerge = {}
    for f2 in fitments:
        if match_props(f1, f2):
            pMerge = {
                    "sku": f1['sku'],
                    "make": f1['make'],
                    "model": f1['model'],
                    "drive": f1['drive'],
                    "years": [y for y in [f1['year'], f2['year']]]
            }
        else:
            pMerge = f2
    if pMerge not in merged:
        merged.append(pMerge)


print(merged)
2
  • 2
    Could you also post up the js you have tried for us to checkout? Commented Oct 2, 2018 at 17:43
  • 1
    No problem - it's Python though - I was using stackblitz for my JS and did not save before I navigated away from page - my apologies. Commented Oct 2, 2018 at 18:22

2 Answers 2

5

Use Array.reduce and Object.values

const vehicles  = [{"sku":"1234","year":"2004","make":"Chevrolet","model":"Avalanche"},{"sku":"1234","year":"2006","make":"Chevrolet","model":"Avalanche"},{"sku":"1234","year":"2009","make":"Chevrolet","model":"Silverado 1500"},{"sku":"1234","year":"2006","make":"Chevrolet","model":"Silverado 1500"}];

let result = Object.values(vehicles.reduce((a,{sku, year, make, model}) => {
  let id = sku + "_" + make + "_" + model;
  if(a[id]) a[id].years.push(year)
  else a[id] = {sku, make, model, years : [year]}
  return a;
},{}));

console.log(result);

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

6 Comments

I like this answer, but be careful using Object.values because its not supported in IE developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
@jman93 I think pretty much everyone uses a transpiler nowadays so you don't really have to care about compatibility.
Maybe, somethings don't transpile and somethings do. Someone would just have to test it
@Nikhil Aggarwal this is great - I had actually toyed with the idea of using an identifier composed of the different keys, but unfortunately never executed it.
@Smitty - Glad to help you :)
|
2

Although this answer overlaps with the one from Nikhil Aggarwal, it is enough different to show it. Instead of fixing the key fields, it focuses on the ones (here just year, but would be easy to extend to others) that have multiple values.

const collect = (vehicles) => Object.values(vehicles.reduce((vs, v) => {
  const {year, ...veh} = v
  const key = JSON.stringify(veh);
  const vehicle = vs[key] || (vs[key] = {years: [], ...veh})
  vehicle.years.push(year)
  return vs
}, {}))

const vehicles = [{"make": "Chevrolet", "model": "Avalanche", "sku": "1234", "year": "2004"}, {"make": "Chevrolet", "model": "Avalanche", "sku": "1234", "year": "2006"}, {"make": "Chevrolet", "model": "Silverado 1500", "sku": "1234", "year": "2009"}, {"make": "Chevrolet", "model": "Silverado 1500", "sku": "1234", "year": "2006"}]

console.log(collect(vehicles))

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.