AtHeartEngineer
AtHeartEngineer

Reputation: 363

How do I turn the values from an object into an array?

I have a function that is polling for temperature data:

{"a":"43",
"b":"43",
"c":"42",
"d":"43",
"e":"40",
"f":"41",
"g":"100",
"h":"42.6"}

I want to be able to graph that data over time, but I can't figure out the best way to map the above data, to something like the below data:

temps: [{
    name: "a",
    data: ["43","42","43"]
  },
    name: "b",
    data: ["43","42","43"]
  },
    etc...
  ]

I have tried the code below, and tried to figure out the javascript map function, but I keep running into scoping problems where "this" isn't the same thing as it was in the parent:

this.temp_names.forEach(function(e){
    if(typeof this.temps[e] == "undefined") {
      this.temps[e] = []
    }
    this.temps.e.unshift(this.sys_telemetry.S.temps)
    if (this.temps.e.length > 10) {
      this.temps.e.pop()
    }
})

where "temp_names" was an array of the keys.

I'm doing this in VueJS, so the "this" is accessing the data in my component.

Upvotes: 1

Views: 88

Answers (4)

kockburn
kockburn

Reputation: 17606

Using Array#from, Object#entries, Array#map and destructuring you could do something like this.

const data={"a":"43","b":"43","c":"42","d":"43","e":"40","f":"41","g":"100","h":"42.6"}

const res = Object.entries(data)
.map(([name, data])=>({name, data:[data]}));

console.log(res);

Alternative using Array#reduce, Map,

const data={"a":"43","b":"43","c":"42","d":"43","e":"40","f":"41","g":"100","h":"42.6"}

const res = Array.from(Object
.entries(data)
.reduce((a,[k,v])=>{
  if(!a.has(k)) a.set(k, []);
  a.get(k).push(v);
  return a;
}, new Map()))
.map(([name, data])=>({name, data}));

console.log(res);

Upvotes: 2

RobG
RobG

Reputation: 147343

It seems to me that you want to be able to add multiple datasets to the data object. One approach is to have a data object with methods that know how to do things like add data to themselves, maybe something like the following. You might want to keep the index property private, and maybe sort it so it's always in a particular order regardless of the order the values are added.

var data0 = {"a":"43",
"b":"43",
"c":"42",
"d":"43"};

var data1 = {"a":"53",
"b":"53",
"c":"52",
"d":"53",
"e":"65"
};

class DataObject {

  constructor (data) {
    this.index = [];
    this.data = [];
    if (data) {
      this.addData(data);
    }
  }

  addData (data) {
    Object.keys(data).forEach(key => {
      let idx = this.index.indexOf(key);
      if (idx == -1) {
        idx = this.index.push(key) - 1;
        this.data.push({name:key, data:[]});
      }
      this.data[idx].data.push(data[key]);
    });
  }
}

// Initialise object with some data
let myData = new DataObject(data0);
console.log(JSON.stringify(myData.data));

// Add more data
myData.addData(data1);
console.log(JSON.stringify(myData.data));

Upvotes: 0

Nick F
Nick F

Reputation: 10102

You might be able to get away with a simpler data structure like, eg. { a: [43, 42, 43], b: [1, 2, 3] }

ie. instead of having separate name and data keys, you could use name as the key, and the data array as the value.

If this would work to represent the timeline for each key, and your initial data is structured like, eg. [{ a: 43, b: 1, c: 3 }, { a: 42, b: 2, c: 3 }], then something like this might be suitable to transform the latter into the former:

const output = {};

temp_data.forEach(x => {
  for (const key in x) {
    const y = x[key];

    if (typeof output[key] === 'undefined') {
      output[key] = [];
    }

    output[key].push(y);
  }
});

This produces an object whose keys match the keys in your data points (eg. "a", "b", "c", etc), and whose values are an array of all the values for each of these keys, which might be suitable for plotting a timeline.

(Incidentally, if you want to plot these as values on a graph, it might be better to treat the values as numbers - eg. 1, 2, 3 - rather than strings - eg. "1", "2", "3").

There are probably more elegant, functional-style ways of doing this, but this might do the job!

Upvotes: 0

Keith
Keith

Reputation: 24181

graph that data over time

Because you want to do this over time, it would make sense to create an array and then using Object.entries, & Array.find, update the results.

Here is an example.

const values1 = 
  {"a":"43", "b":"43", "c":"42", "d":"43", "e":"40", "f":"41",
  "g":"100", "h":"42.6"};
  
const values2 = 
  {"c":"44", "e":"39"};
  

const results =  [];

function addData(data) {
  Object.entries(data).forEach(([k, v]) => {
    let find = results.find(f => f.name === k);
    if (!find) {
      find = {
        name: k,
        data: []
      }
      results.push(find);
    }
    find.data.push(v);
  });
}

addData(values1); //data packet one arrives
addData(values2); //data packet two arrives
  
console.log(results); //results contains both data packet one & two.

Upvotes: 1

Related Questions