I have a list of single key value pairs, where the key is a 2 part string that describes where the value should be plotted on a table. This is the first time I've asked a questions on SO so please go easy on me.
let tiles = [
{ 'A~baz': 'x' },
{ 'A~buzz': 'o' },
{ 'A~fam': '' },
{ 'B~baz': 'x' },
{ 'B~buzz': '' },
{ 'B~fam': '' },
{ 'C~baz': 'x' },
{ 'C~buzz': 'x' },
{ 'C~fam': 'x' }
]
I want to convert it into the below format.
[
{ _id: 'A', baz: 'x', buzz: 'o', fam: '' },
{ _id: 'B', baz: 'x', buzz: '', fam: '' },
{ _id: 'C', baz: 'x', buzz: 'x', fam: 'x' }
]
Note I will need to perform this operation on hundreds of thousands of key value pairs.
What I have done so far, this works, but I was hoping there could be places I can make improvements.
let tiles = [
{ 'C~fam': "x" },
{ 'B~buzz': "" },
{ 'B~fam': "" },
{ 'A~fam': "" },
{ 'A~buzz': "o" },
{ 'B~baz': "x" },
{ 'A~baz': "x" },
{ 'C~baz': "x" },
{ 'C~buzz': "x" },
];
// I thought it would help to sort the array
tiles.sort((a, b) => Object.keys(a)[0].localeCompare(Object.keys(b)[0]));
let obj = {};
tiles.forEach((kvp) => { //kvp = key value pair
let [row,col] = Object.keys(kvp)[0].split('~') //destruct by '~'
let val = Object.values(kvp)[0];
obj[row] = obj[row] ?? {}
obj[row][col] = val;
})
let keys = Object.keys(obj);
let values = Object.values(obj)
let output = [];
for (let i = 0, len = keys.length; i < len; i ) {
output.push(Object.assign({_id : `${keys[i]}`}, values[i]));
}
CodePudding user response:
You condemned your algorithm's complexity to O(nlog(n)) by sorting the array. You can solve this problem without the need to sort it. Since we must iterate through all of the array, the best complexity possible would be O(n). Assuming the input format will always remain the same, try this:
function changeFormat (arr){
const hash = {}
arr.forEach(element => {
const key = Object.keys(element)[0];
const _id = key[0];
if (hash[_id] === undefined)
hash[_id] ={_id, baz:'', buzz:'', fam:''};
const type = key.slice(2);
hash[_id][type] = element[key];
});
return Object.values(hash);
}
CodePudding user response:
You can put this code in a function and reuse, this code will work even if the props change from baz, buzz, fam.
let requiredFormat = tiles.reduce((acc, tile) => {
let keys = Object.keys(tile);
let firstKey = keys[0];
let firstKeyArray = firstKey.split("~");
let id = firstKeyArray[0];
let propName = firstKeyArray[1];
let objWithId = acc.find(obj => obj._id === id);
if(objWithId) {
let accumulatorWithoutCurrentObject = acc.filter(obj => obj._id !== id);
let upadtedObjWithId = {...objWithId, [propName]: tile[firstKey]};
let updatedAcc = [
...accumulatorWithoutCurrentObject,
upadtedObjWithId
];
return updatedAcc;
}
let updatedAcc = [
...acc,
{_id: id, [propName]: tile[firstKey]}
];
return updatedAcc;
}, []);
CodePudding user response:
Here you've got single loop solution
let res = {};
let arrayRes = [];
tiles.forEach(function(tile) {
let tileKey = Object.keys(tile)[0];
let tileKeySplitted= tileKey.split('~');
let column = tileKeySplitted[0];
let key = tileKeySplitted[1];
if (res[column] == null) {
res[column] = {'_id': column};
arrayRes.push(res[column]);
}
res[column][key] = tile[tileKey];
});
console.log(arrayRes);