3

I'm looking to normalise some data returned from an API. Already using underscore within the project.

var res = [{
    badge_no: 123,
    id: 1,
    name: 'bob'
  }, {
    badge_no: 456,
    id: 2,
    name: 'bill'
  }, {
    badge_no: 789,
    id: 3,
    name: 'ben'
  },
  // etc
];

I'm looking to create a data structure that looks like:

var normalisedRes = [{
  1: {
    badge_no: 123,
    id: 1,
    name: 'bob'
  }
}, {
  2: {
    badge_no: 456,
    id: 2,
    name: 'bill'
  }
}, {
  3: {
    badge_no: 789,
    id: 3,
    name: 'ben'
  }
}];

It is important that I keep the id within the obj. I believe I can accomplish this with reduce but I'm struggling.

Thanks for your help!

EDIT: This question has now been answered.

From some of the advice on here, I have decided to normalise the data to return an obj which looks like:

{ '1': {data}, '2':{data}, '3':{data} }

To do this I used reduce, as I originally thought I should:

var normalised = res.reduce((acc, person) => { acc[person.id] = person; return acc; }, {});

Thanks again for all the answers!

ste
  • 53
  • 2
  • 8
  • 1
    Can you share your code that you have tried so far? – Rajesh Jan 30 '17 at 16:27
  • 4
    So you want an array of objects, with each of those objects containing a single key (its `id`)? How is that a "better" or normalized version of what you started with? Why do you want that structure? – gen_Eric Jan 30 '17 at 16:28
  • 3
    Final structure makes no sense. Why would you need an array to wrap one object? – charlietfl Jan 30 '17 at 16:33
  • 1
    Do you want the keys to be `ID`s or `indexes (+1)`? – ibrahim mahrir Jan 30 '17 at 16:46
  • 2
    Please, edit in your question your last comment about keys being IDs. Also, avoid editing an answer into your question and instead, accept one of the answers, comment on it with your final decision if necessary. If none of the answers fit your needs, you are encouraged to provide your own and accept it. – Emile Bergeron Jan 30 '17 at 17:56
  • Duplicate of https://stackoverflow.com/questions/26264956/convert-object-array-to-hash-map-indexed-by-an-attribute-value-of-the-object – loop May 03 '21 at 05:57

5 Answers5

3

You could use Array#map with an object and set the key with id and return the object.

var array = [{ badge_no: 123, id: 1, name: 'bob' }, { badge_no: 456, id: 2, name: 'bill' }, { badge_no: 789, id: 3, name: 'ben' }],
    result = array.map(function (a) {
        var o = {};
        o[a.id] = a;
        return o;
   });

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

With ES6, you could use a computed property.

var array = [{ badge_no: 123, id: 1, name: 'bob' }, { badge_no: 456, id: 2, name: 'bill' }, { badge_no: 789, id: 3, name: 'ben' }],
    result = array.map(a => ({ [a.id]: a }));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • 1
    Though its correct answer, should you not wait for OP to share efforts? – Rajesh Jan 30 '17 at 16:30
  • I think the link is wrong... it isn't [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map), it is [`Array.prototype.map`](https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Array/map) – NonPolynomial Jan 30 '17 at 16:40
1

You can do this with Array#map()

var res = [{badge_no:123, id:1, name:'bob'},{badge_no:456, id:2, name:'bill'},{badge_no:789, id:3, name:'ben'}];

var result = res.map(e => ({[e.id]: e}))
console.log(result)

If you want you can also use reduce() but map() should get the job done.

var res = [{badge_no:123, id:1, name:'bob'},{badge_no:456, id:2, name:'bill'},{badge_no:789, id:3, name:'ben'}];

var result = res.reduce((r, e) => (r.push({[e.id]: e}), r), [])
console.log(result)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
1

You cant use integers as key in an object. So your example isnt possible. See this relatied issue: Javascript: Using integer as key in associative array?

Community
  • 1
  • 1
  • 3
    you can use any type of key, it just will get autoboxed to a string – NonPolynomial Jan 30 '17 at 16:32
  • 3
    It is generally bad practice since it will force you to access the property inside the object with e.g. console.log(normalisedRes["3"]) instead of doing it like console.log(normalisedRes.3) wich will yield an error. – Nico Mollema Jan 30 '17 at 16:35
  • 3
    `normalisedRes[3]` works too and within a automated process where the keys will be computed, you have to access the values with bracket syntax – NonPolynomial Jan 30 '17 at 16:38
  • 1
    Though it is bad practice, this is what OP wants. This answer is half true. The example **is** possible. – Emile Bergeron Jan 30 '17 at 16:47
0

Aren't these solutions counter intuitive thou, the point of using an HashTable over an array is that if you have to use Array.find((item)=>{...}) it has to go through each record to find the one you want, reduce will go through each item in the array, and map will return back a new array, ie: you will get an array with the objectKey:{...object}, the best thing to do will be to return an Hash from your backend, This is actually what firebase does for example

0

_.indexBy does exactly what is required.

Julian
  • 4,176
  • 19
  • 40