0

How can I combine two objects into an array while also keeping the key values within the objects? I've found solutions to merging objects but none of them seem to keep the key values.

My code is creating new cars. I want to organize my new cars into an array while later, being able to organize them by model, model year, color, etc. Some of that organizational logic has not been implemented yet as I'm focusing on getting the object merging ironed out before the data becomes too long.

class Car {
    constructor(type, model_year) {
        this.type = type,
        this.model_year = model_year

    }
}

class Tesla extends Car{
    constructor(type, model_year){

        super(type, model_year)
    }
}

let myTesla1 = new Tesla("Sedan", 2015)
let myTesla2 = new Tesla("Coupe", 2014)

My desired output would be:

let teslas = // Here is what I'm failing to implement
console.log(teslas)
// ["type", "Sedan", "model_year", "2015", "type", "Coupe", "model_year", "2014"]

Maybe my logic wrong here. I'm sure there is a better way to organize these cars but I'm failing to figure that out as well.

My Attempt

I attempted to map over the object using entries like so:

let teslas = Object.entries(myTesla1).map(([key, value]) => ({key, value}));
console.log(teslas);

But my output wasn't exactly what I was looking for as it put the key values like so:

[ { key: 'type', value: 'Sedan' },
  { key: 'model_year', value: 2015 } ]

Thanks in advance for any help. I'm fairly new to this so please excuse anything that should be done a better way.

Edward
  • 245
  • 1
  • 4
  • 12
  • _I'm sure there is a better way to organize these cars but I'm failing to figure that out as well._ I did wonder when looking at this why you would want to flatten your objects in a way that makes the association between each car and its attributes dependent on their order in the array. Seems like it would be better to have an array with cars as top-level containers, with distinct key-values with that container. But that's up to you, really. – Matt Morgan Feb 24 '19 at 20:23

5 Answers5

3

Use the function reduce instead.

class Car {
  constructor(type, model_year) {
    this.type = type,
      this.model_year = model_year
  }
}

class Tesla extends Car {
  constructor(type, model_year) {
    super(type, model_year)
  }
}

let myTesla1 = new Tesla("Sedan", 2015);
let myTesla2 = new Tesla("Coupe", 2014);

let teslas = [];

// Concatenate the entries [key, value] to the accumulator
[myTesla1, myTesla2].forEach((obj) => teslas = teslas.concat(Object.entries(obj)
              .reduce((a, entries) => a.concat(entries), [])));

console.log(teslas);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ele
  • 33,468
  • 7
  • 37
  • 75
1

You can use Array.reduce() and Object.entries() to do this. For each entry of each car, you push the property's name and then you push the property's value in your output array:

class Car {
  constructor(type, model_year) {
    this.type = type,
    this.model_year = model_year
  }
}

class Tesla extends Car{
  constructor(type, model_year){
    super(type, model_year)
  }
}

const tesla1 = new Tesla("Sedan", 2015);
const tesla2 = new Tesla("Coupe", 2014);

const teslas = [tesla1, tesla2].reduce((acc, car) => {
  Object.entries(car).forEach(([key, val]) => acc.push(key, val));
  return acc;
}, []);

console.log(teslas);
jo_va
  • 13,504
  • 3
  • 23
  • 47
1

I'm going to work with your comment: I'm sure there is a better way to organize these cars but I'm failing to figure that out as well

I'm going to suggest that what you want is an array with one entry per car, and that entry is a simple map of the key-value pairs. You can use Object.assign to accomplish the mapping from your class instances to a plain object:

class Car {
  constructor(type, model_year) {
    this.type = type,
    this.model_year = model_year
  }
}

class Tesla extends Car {
  constructor(type, model_year) {
    super(type, model_year)
  }
}

let myTesla1 = new Tesla("Sedan", 2015)
let myTesla2 = new Tesla("Coupe", 2014)

const teslas = [myTesla1, myTesla2]

const carListWithKeyValues = teslas.map(tesla => Object.assign(tesla))

console.log(carListWithKeyValues)

/*
output:

[
  {
    "type": "Sedan",
    "model_year": 2015
  },
  {
    "type": "Coupe",
    "model_year": 2014
  }
]

*/
Matt Morgan
  • 4,900
  • 4
  • 21
  • 30
  • This worked perfect, thanks a lot. If I wanted to take it a step further and `sort` these collection of Teslas based on `type` or `model_year`, is that feasible with this output since it's an array of different objects? – Edward Feb 25 '19 at 16:57
  • Yes. `Array.sort` accepts a custom function for sorting, there's another SO answer on this if you are sorting by string values: https://stackoverflow.com/a/43816588/3084820 – Matt Morgan Feb 25 '19 at 18:35
0

You can do it in this simple way too

<script type="text/javascript">
    class Car {
    constructor(type, model_year) {
        this.type = type,
        this.model_year = model_year

    }
}

class Tesla extends Car{
    constructor(type, model_year){

        super(type, model_year)
    }
}

let myTesla1 = new Tesla("Sedan", 2015)
let myTesla2 = new Tesla("Coupe", 2014)

var objects = [myTesla1, myTesla2];

var results = [];

objects.forEach(function(o){

    for(var key in o){
        results.push(key);
        results.push(o[key]);
    }
});

console.log("myTesla1", myTesla1);
console.log("myTesla2", myTesla2);

console.log("results", results);
</script>
muasif80
  • 5,586
  • 4
  • 32
  • 45
0

You can use concat.apply() and Object.entries() like so:

class Car {
    constructor(type, model_year) {
        this.type = type,
        this.model_year = model_year

    }
}

class Tesla extends Car{
    constructor(type, model_year){

        super(type, model_year)
    }
}

let myTesla1 = new Tesla("Sedan", 2015)
let myTesla2 = new Tesla("Coupe", 2014)

let teslas = [].concat.apply([], Object.entries(myTesla1).concat(Object.entries(myTesla2)));
Jack Bashford
  • 43,180
  • 11
  • 50
  • 79