1

Data is useless unless it is well structured. I want to convert array of objects into a more meaningfully structured object via vanilla JavaScript and by this - to lessen entropy in the world :)

Companies' values form nested named arrays as well as vehicles' values form nested named objects. The hardest task was to set if-statements dynamically. I got stuck in the end of the code, yet, hoping that a JS professional could help me out.

// Source data format

var inputs = [
    {"vehicle":"car", "company":"Toyota", "model":"Corolla"},
    {"vehicle":"car", "company":"Toyota", "model":"Rav4"},
    {"vehicle":"car", "company":"Toyota", "model":"Camry"},
    {"vehicle":"car", "company":"Chevrolet", "model":"Malibu"},
    {"vehicle":"car", "company":"Chevrolet", "model":"Camaro"},
    {"vehicle":"rocket", "company":"Tesla", "model":"SpaceX"}
];

// Target data format

const data = {
    car:{
        Toyota:[
            {"vehicle"="car","company"="Toyota", "model"="Corolla"},
            {"vehicle"="car","company"="Toyota", "model"="Rav4"},
            {"vehicle"="car","company"="Toyota", "model"="Camry"}
        ],
        Chevrolet:[
            {"vehicle"="car","company"="Chevrolet", "model"="Malibu"},
            {"vehicle"="car","company"="Chevrolet", "model"="Camaro"}
        ]
    },
    rocket:{
        Tesla:[
            {"vehicle"="rocket","company"="Tesla", "model"="SpaceX"}
        ]
    }
};

// Unfinished solution

// Get all vehicle names.
var vehicles = [];
for (var [key, obj] of inputs.entries()) {
    vehicles.push(obj.vehicle);
}

// Single out only unique vehicle names.
var uniqueVehicles = [...new Set(vehicles)];

// Get all company names.
var arr = [];
for (var [key, obj] of inputs.entries()) {
    arr.push(obj.company);
}

// Single out only unique company names.
var uniqueCompanies = [...new Set(arr)];

// Group objects into arrays by company names.
var dataProperties = {};
for (var comp of uniqueCompanies) {
    dataProperties[comp] = inputs.filter(obj => obj.company === comp);  
}

// Group objects into arrays by vehicle names.
var data = {};
for (var vehi of uniqueVehicles) {
    data[vehi] = inputs.filter(o => o.vehicle === vehi);
}
// data;
// dataProperties;

2 Answers 2

2

Here's how i would do it:

function transform(data) {
  let result = {};
  data.forEach(element => {
    // Reuse the existing vehicle object, or create an empty one if it doesn't exist
    result[element.vehicle] = result[element.vehicle] || {};
    // Reuse the existing company array, or create an empty one if it doesn't exist
    result[element.vehicle][element.company] = result[element.vehicle][element.company] || [];
    result[element.vehicle][element.company].push(element);
  })
  return result;
}

const inputs = [
  {"vehicle":"car", "company":"Toyota", "model":"Corolla"},
  {"vehicle":"car", "company":"Toyota", "model":"Rav4"},
  {"vehicle":"car", "company":"Toyota", "model":"Camry"},
  {"vehicle":"car", "company":"Chevrolet", "model":"Malibu"},
  {"vehicle":"car", "company":"Chevrolet", "model":"Camaro"},
  {"vehicle":"rocket", "company":"Tesla", "model":"SpaceX"}
];

const output = transform(inputs);
console.log(output);

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

2 Comments

Thank you, Nicholas! If I may, would you please describe the logic how did you make it?
I'm not sure how much there is i can describe. The logic is: for each element of the input array, create the corresponding vehicle object and company array, then insert the element into that array. The only extra bit is to reuse any vehicle objects or company arrays that already exist.
1

You could take a more advanced version with an array of the wanted keys for nesting the wanted properties. This approach is a bit different than the other answer.

The key part is to generate, if necessary and return the last array for pushing an object to the result set,

groups.reduce((p, k, i, { length }) => p[o[k]] = p[o[k]] || (i + 1 === length ? [] : {}), r)

where you have

  • p an object as accumulator, starting with the final result object,
  • k the key for grouping,
  • i the actual index of the groups array,
  • a destructured length of the groups array for a following check, if the last item is used.

Inside of the callback, the value of the wanted property o[k] is used to access the object p and if not truthy, like undefined, then an array of if the last key is taken, then an array is taken.

var array = [{ vehicle: "car", company: "Toyota", model: "Corolla" }, { vehicle: "car", company: "Toyota", model: "Rav4" }, { vehicle: "car", company: "Toyota", model: "Camry" }, { vehicle: "car", company: "Chevrolet", model: "Malibu" }, { vehicle: "car", company: "Chevrolet", model: "Camaro" }, { vehicle: "rocket", company: "Tesla", model: "SpaceX" }],
    groups = ["vehicle", "company"],
    result = array.reduce((r, o) => {
        groups
            .reduce((p, k, i, { length }) => p[o[k]] = p[o[k]] || (i + 1 === length ? [] : {}), r)
            .push(o);
        return r;
    }, {});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

2 Comments

Truely interesting and sophisticated solution! I guess, I will be able to perceive it in about 5 years :) Never the less, thank you very much, Nina!
@MaksymDudyk, you grok it earlier, i am sure.

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.