-1

I have an object like this -

const obj = {
    'veh1': 'Car',
    'veh2': 'Bicycle',
    'veh3': 'Truck',
    'wheels1': '4',
    'wheels2': '2',
    'wheels3': '8'
}

I want an object which have entries mapped like- veh1 to wheels1, veh2 to wheels2, veh3 to wheels3 and so on The resultant object should be like this-

const result = {
    'Car': '4',
    'Bicycle': '2',
    'Truck': '8'
}

I know, we can do it directly like this -

{
   [obj.veh1]: obj.wheels1,
   [obj.veh2]: obj.wheels2,
   [obj.veh3]: obj.wheels3
}

But what will be the better way? The number of entries can be any number 'n'.

How can I attain this through javascript?

Peter Seliger
  • 4,001
  • 1
  • 20
  • 27
Vivek kumar
  • 1,632
  • 1
  • 14
  • 29
  • Loop through all object keys that start with `veh` and then find the matching `wheel` value. – Terry Oct 22 '20 at 20:10

3 Answers3

1

You can do something like this:

const vehicles = {};
const wheels = {};
const result = {};

for (key in obj) {
  if (key.startsWith("veh")) {
    const id = key.replace("veh", "");
    vehicles[id] = obj[key];
    if (wheels.hasOwnProperty(id)) {
      result[vehicles[id]] = wheels[id];
    }
  } else if (key.startsWith("wheels")) {
    const id = key.replace("wheels", "");
    wheels[id] = obj[key];
    if (vehicles.hasOwnProperty(id)) {
      result[vehicles[id]] = wheels[id];
    }
  }
}
Raphael Koh
  • 111
  • 9
  • This approach only works for keys that start with either `veh` or `wheels`. For it has to be adopted to any changes of an object's key pattern, it is not a generic one. – Peter Seliger Oct 22 '20 at 22:34
  • @PeterSeliger I assumed the question was asking for this specific example and not a generic one. This approach has a 1-pass, linear running time whereas your solution requires 2 passes and sorting. Maybe OP can clarify their use case. – Raphael Koh Oct 22 '20 at 22:37
  • ... understood and upvoted. BTW your approach is much more robust than the one of *ZaO Lover* because the latter does rely on an exact key order. – Peter Seliger Oct 23 '20 at 09:34
1
  1. Create entries (key value pairs) from the provided object.
  2. Sort the entries by each of an entry's key.
  3. Finally create a new objects from the upper (or left) as well the lower (or right) half of the before sorted entries.

function localeCompare(a, b) {
  return (a.localeCompare && b.localeCompare
    && a.localeCompare(b))
    || (((a < b) && -1) || ((a > b) && 1) || 0);
}

function compareEntriesByKey(entryA, entryB) {
  return localeCompare(entryA[0], entryB[0]);
}

function createKeyValuePairFromSortedEntryHalfs(obj, $, idx, entries) {
  if (((idx + 1) % 2) === 0) {
 
    const keyIdx = ((idx - 1) / 2);
    const valueIdx = (keyIdx + Math.floor(entries.length / 2));

    const key = entries[keyIdx][1];
    const value = entries[valueIdx][1];

    obj[key] = value;
  }
  return obj;
}


const obj = {
  'wheels3': '8',
  'veh3': 'Truck',
  'wheels1': '4',
  'veh1': 'Car',
  'wheels2': '2',
  'veh2': 'Bicycle',
}
const result = Object
  // (1) create entries (key value pairs) from the provided object.
  .entries(obj)
  // (2) sort the entries by each of an entry's key.
  .sort(compareEntriesByKey)
  // (3) finally create a new objects from the upper (or left) as
  //     well the lower (or right) half of the before sorted entries.
  .reduce(createKeyValuePairFromSortedEntryHalfs, {});

console.log('result :', result);

console.log('obj', obj);
console.log(
  'Object.entries(obj).sort(compareEntriesByKey)',
  Object.entries(obj).sort(compareEntriesByKey)
);

console.log(
  'proof of being a generic approach...', `
  Object.entries({
    'foo-biz': 'biz',
    'x': 111,
    'foo-baz': 'baz',
    'y': 222,
    'foo-bar': 'bar',
    'z': 333,
  }).sort(
    compareEntriesByKey
  ).reduce(
    createKeyValuePairFromSortedEntryHalfs,
    {}
  ) =>`, Object.entries({
    'foo-biz': 'biz',
    'x': 111,
    'foo-baz': 'baz',
    'y': 222,
    'foo-bar': 'bar',
    'z': 333,
  }).sort(
    compareEntriesByKey
  ).reduce(
    createKeyValuePairFromSortedEntryHalfs,
    {}
  )
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Peter Seliger
  • 4,001
  • 1
  • 20
  • 27
-1
const obj = {
  'veh1': 'Car',
  'veh2': 'Bicycle',
  'veh3': 'Truck',
  'wheels1': '4',
  'wheels2': '2',
  'wheels3': '8'
}

let res = {};
let keys = Object.keys(obj);
let i;
for(i = 0; i < keys.length; i ++) {
  if(keys[i].slice(0, 3) === 'veh') {
    res[obj[keys[i]]] = obj[`wheels${keys[i].slice(3)}`];
  }
}

console.log(res);
ZaO Lover
  • 449
  • 1
  • 12
  • One can not rely on the key order, especially if the key value pairs will not be provided in such an ideal way like with the OP's code example. A generic approach, which finally creates the new key value pairs, also does not need to make any assumptions about any of the original object's keys as done within your example. – Peter Seliger Oct 22 '20 at 21:59
  • I like this answer better than mine. It does the same thing but less lines. One question: why do you need to cast to an int? – Raphael Koh Oct 22 '20 at 22:39