3

I am still learning JavaScript, so I apologize in advance if this seems a remedial question.

I am receiving data from an API call in the form of an array, like so:

arr = ['topic1',497,'topic2',591,'topic3',17,'topic4',980]

Though it's not evident from that array, the number following each topic string is the count of the previous topic.

I want to work with this data in a React app, i.e., map it to a table or other data structure. But that's exceedingly difficult to do when the values are anonymous like this.

So, I want to take this array and convert it into an object with key/value pairs. So, after working some kind of loop/filter/map/etc. on the array, I need to end up with this:

newArr = [
  {topic: 'topic1', count: 497},
  {topic: 'topic2', count: 591},
  {topic: 'topic3', count: 17},
  {topic: 'topic4', count: 980},
]

I have tried SO many techniques, ranging from using dictionaries, Maps, map, filter, forEach, for ... in, and more techniques than I even remember at this point. And yes, I searched many web pages and forums. The problem is, my question includes some of the very building blocks of JavaScript, so the answers I found were never specific enough for my problem.

I did successfully filter out the even and odd elements in the array, like so:

let x = arr.filter((element, index) => {
  return index % 2 === 0; filter elements located at an even index
});

let y = arr.filter((element, index) => {
  return index % 2 === 1; filter elements located at an odd index
});

But I've never successfully gotten the result I need. Can anybody please help point me in the right direction?

I'm using React, so feel free to suggest modern JS techniques. Thanks!

Reporter
  • 3,897
  • 5
  • 33
  • 47
patrickrs
  • 57
  • 8
  • 1
    Because you are a new user, a useful advice for you: arrays and objects are used in many languages. So please add a properly language tag to your question (I did it for you at this one). – Reporter Feb 27 '18 at 15:08
  • If both arrays are equal, loop them and create an object out of it and add to an array! – Bharadwaj Feb 27 '18 at 15:08
  • 1
    Possible duplicate of [Is it possible to add dynamically named properties to JavaScript object?](https://stackoverflow.com/questions/1184123/is-it-possible-to-add-dynamically-named-properties-to-javascript-object) – GalAbra Feb 27 '18 at 15:12
  • 1
    Thanks, reporter...good to know! Bharadwaj, I think I get that, but there is only a single array consisting of topic, count, topic, count, etc. So, there is an association between each pair of items. By combining two filtered arrays this way, can I be sure the resulting object maintains the correct relationship in the correct order? – patrickrs Feb 27 '18 at 15:12
  • :) got it, then you should use `forEach` – Bharadwaj Feb 27 '18 at 15:14
  • 1
    GalAbra, if it is a duplicate, I can't make heads nor tails of that other post. :) What I have going for me in this instance is that the array structure I'm getting back from the API never changes...only the data does. So, I need some kind of function to take that data, however long or short the array, and map each element to either "topic" or "count", as the case may be. I never need to dynamically add or remove properties. I make the call, get the array, perform the conversion. I then have a nice object I can map to a table or whatever I want. – patrickrs Feb 27 '18 at 15:16

3 Answers3

4

You need to loop through your API response and build the objects from the array.

let objectArray = []

for(let i = 0; i < arr.length - 1; i+=2){
    objectArray.push({"topic": arr[i], "count": arr[i+1]})
}

I'm sure there's an easier way to do it, but this will get you what you need.

See it in action on jsFiddle: https://jsfiddle.net/L6023fn6/1/

Mario Murrent
  • 712
  • 5
  • 24
NiftyAsp
  • 620
  • 4
  • 10
  • Thank you so much!! That is exactly what I was trying to do. Shocking how simple it actually was! I have a lot to learn... – patrickrs Feb 27 '18 at 15:30
1

You can use array.reduce for this which takes an array and emits an aggregated value, array, object, or something else. A full implementation would be:

const newArr = arr.reduce((fonts, value, index) => {
   if (0 === index % 2) {
     fonts.push({ topic: value });
   } else {
     // output array will be half the size of the input hence the / 2
     fonts[Math.ceil(index / 2 - 1)].count = value;
   }

   return fonts;
}, []);

If you're willing to use an external library like lodash you can make this even easier since it will chunk the array for you.

const newArr = _.zipWith(_.chunk(arr, 2), a => ({ topic: a[0], count: a[1] }));
Explosion Pills
  • 188,624
  • 52
  • 326
  • 405
0

From your question, the arr is a string,number... pattern, going by that i feel you can do this.

const arr = ['topic1',497,'topic2',591,'topic3',17,'topic4',980];
const result = [];

for(let i=0; i<arr.length; i+=1) {
 typeof arr[i] === 'string' 
 ?
  result.push({topic: arr[i], count: arr[i+1]})
:
null;

}