Invert key value in js object

Viewed 502

I can't figure out how I can change :

{"first":["de"], "second":["ab","de"], "third":["de"]}

to:

{"de":["first", "second", "third"], "ab":["second"]}

I want to associate unique values with list of containing keys. What I tried(but I think I'm far from it):

 const data = {
      "first":["de"],
      "second":["ab","de"],
      "third":["de"]
    }
    
    console.log(
      Object
      .keys(data).reduce(function(obj, key) {
        obj[data[key]] = key;
        return obj;
      }, {})
    )

Thanks for your help!

6 Answers

Object.entries to get it into an array, reduce to build the new object, and forEach to loop over the array

const o = {"first":["de"], "second":["ab","de"], "third":["de"]}

const result = Object.entries(o).reduce((obj, [key, arr])=>{
  arr.forEach(lng => {
    obj[lng] = obj[lng] || [];
    obj[lng].push(key);
  })
  return obj
}, {});

console.log(result);

You have to loop the array and for each item in the array check if an array for that value exists in the accumulator or not before adding it:

let result = Object.entries(data).reduce((acc, [key, arr]) => { // for each key-array of the original object
  arr.forEach(value => {                                        // for each value in the array
    acc[value] = acc[value] || [];                              // create an array in the output object if it doesn't already exist
    acc[value].push(key);                                       // push the key to it
  });

  return acc;
}, {});

I also used Object.entries with each entry desctuctured as [key, arr] so I don't have to use the extra [key] to get the array while using Object.keys.

Demo:

let data = {"first":["de"], "second":["ab","de"], "third":["de"]};

let result = Object.entries(data).reduce((acc, [key, arr]) => {
  arr.forEach(value => {
    acc[value] = acc[value] || [];
    acc[value].push(key);
  });

  return acc;
}, {});

console.log(result);

On reduce callback, data[key] is an array of string values. So it is needed to loop that data[key] array values and assign value for each array item.

const data = {
  "first":["de"],
  "second":["ab","de"],
  "third":["de"]
}

console.log(
  Object.keys(data).reduce(function(obj, key) {
    data[key].forEach((val) => {
      obj[val] ? obj[val].push(key) : obj[val] = [ key ];
    });
    return obj;
  }, {})
)

Try this (naive solution), if this works for you

const data = { first: ["de"], second: ["ab", "de"], third: ["de"] };

let dataMap = new Map();
Object.keys(data).forEach((key) => {
  data[key].forEach((val) => {
    if (dataMap.has(val)) {
      dataMap.set(val, [...dataMap.get(val), key]);
    } else {
      dataMap.set(val, [key]);
    }
  });
});

let nData = [];
dataMap.forEach((value, key) => {
  nData.push({
    [key]: value
  });
});

console.log(nData);

You could take a double reduce with the entries.

const
    data = { first: ["de"], second: ["ab", "de"], third: ["de"] },
    result = Object
        .entries(data)
        .reduce((o, [value, keys]) => keys.reduce((q, key) => {
            (q[key] ??= []).push(value);
            return q;
        }, o), {});

console.log(result);

I'm not using reduce but here's a "bruteforce" for your problem which works:

res = {};

Object.keys(data).forEach(key => {
      data[key].forEach(el => {
          if (! res[el])
            res[el] = [];
        
         if (! res[el].includes(key))
            res[el].push(key);
      })
  });
Related