group object keys with the same value

I have an object

var myObject = {"audi": "gas", "tesla": "electric", "bmw": "electric", "mercedes": "electric"}

and I want to group all keys with same value in one string like using only es5

tesla bmw mercedes: electric. audi: gas

I used combination of Object.keys and Object.values but it didn’t work for me

var res = ''
Object.keys(myObject).map(function(key) {
    Object.values(myObject).map(function(val) {
        if (myObject[key] === val) {
            kes = {
                [res.concat(key)]: val
            }
        }
    })
})

Answer

It would make more sense to group by ‘fuel’. For that, you can use a reducer.

In the snippet a few different roads to Rome …

See also…

const logElem = document.querySelector(`pre`);
var myObject = {
  audi: "gas",
  tesla: "electric",
  bmw: "electric",
  mercedes: "electric"
};

const byFuel = Object.entries(myObject)
  .reduce((acc, [key, value]) =>
    ({ ...acc, [value]: (acc[value] || []).concat(key) }), {});

logElem.textContent = `***By fuel (ES6)***n ${
  JSON.stringify(byFuel, null, 2)}`;

// to swap keys and values from [byFuel]
const byCars = Object.entries(byFuel)
  .reduce((acc, [key, value]) => ({ ...acc,
    [value.join(`,`)]: key
  }), {});

logElem.textContent += `nn***By cars from byFuel (ES6)***n${
  JSON.stringify(byCars, null, 2)}`;

// Use one reducer (ES6)
const byCarsInOne = Object.entries(myObject)
  .reduce((acc, [key, value]) => {
    const keysAggregatedAsSingleKey = Object.keys(myObject)
      .filter( key => myObject[key] === value )
      .join(`,`);
    return acc[keysAggregatedAsSingleKey] 
      ? acc 
      : { ...acc, [keysAggregatedAsSingleKey]: value };
  }, {});

logElem.textContent += `nn***One reducer***n${
  JSON.stringify(byCarsInOne, null, 2)}`;


// ES5 (really necessary? All modern browsers support es6)
var byFuelEs5 = {};
var byCarsEs5 = {};

for (var key in myObject) {
  var ky = myObject[key];
  byFuelEs5[ky] = ky in byFuelEs5 
    ? byFuelEs5[ky].concat(key) 
    : [key];
}

logElem.textContent += `nn***ES5***n${
  JSON.stringify(byFuelEs5, null, 2)}`;

for (var key in byFuelEs5) {
  byCarsEs5[byFuelEs5[key].join(`,`)] = key;
}

logElem.textContent += `nn${
  JSON.stringify(byCarsEs5, null, 2)}`;

// Object.keys ES5, not very efficient
// (makes you *really* want to use ES6 ;)
var cars = Object.keys(myObject);
var byCarsEs5_2 = cars
  .map( function(key) {return [myObject[key], key]; })
  .map( function(kv) {
    var fuel = kv[0];
    var comma = this[fuel] ? "," : "";
    this[fuel] = (this[fuel] || "") + comma + kv[1];
    return this; }, {} )
  .map( function(obj) {
    var keys = Object.keys(obj)
      .map( key => this[obj[key]] = key );
    return this;
  }, {}).shift();
  
logElem.textContent += `nn***Object.keys and map ES5***n${
      JSON.stringify(byCarsEs5_2, null, 2)}`;

// Finally, reduce from Object.keys my be more efficient
var byCarsEs5_3 = cars
  .reduce( function(acc, car) {
    var fuel = myObject[car];
    
    if (!~acc.fuels.indexOf(fuel)) {
      acc.fuels.push(fuel);
      var carsByFuel = cars.filter(key => myObject[key] === fuel);
      acc.result[carsByFuel] = fuel;
    }

    return acc; 
  }, {fuels: [], result: {}} ).result;

logElem.textContent += `nn***ES5 one reducer from  Object.keys***n${
  JSON.stringify(byCarsEs5_3, null, 2)}`;
<pre></pre>