1

I need to convert one array to in specific data format to display the chart.

chrat.js library require data in this format

dataset = [ { label: 'one', data: []}, 
           {label: 'two', data: []}
        ];

and I receive the response data in another format in random order so need to change appropriately with the respective label.

here is my code and trial.

const dataset = [
    {
        detail: {
            team: [
                { name: 'alpha', game: 1 },
                { name: 'beta', game: 1 },
                { name: 'gamma', game: 1 },
                { name: 'delta', game: 1 },
                { name: 'echo', game: 1 }
            ]
        }
    },
    {
        detail: {
            team: [
                { name: 'alpha', game: 2 },
                { name: 'beta', game: 2 },
                { name: 'echo', game: 2 },
                { name: 'gamma', game: 2 },
                { name: 'delta', game: 2 }
            ]
        }
    },
    {
        detail: {
            team: [
                { name: 'echo', game: 1 },
                { name: 'delta', game: 0 },
                { name: 'beta', game: 0 },
                { name: 'gamma', game: 0 },
                { name: 'alpha', game: 0 }
            ]
        }
    },
    {
        detail: {
            team: [
                { name: 'delta', game: 0 },
                { name: 'echo', game: 0 },
                { name: 'beta', game: 0 },
                { name: 'gamma', game: 1 },
                { name: 'alpha', game: 0 }
            ]
        }
    },
    {
        detail: {
            team: [
                { name: 'delta', game: 0 },
                { name: 'echo', game: 0 },
                { name: 'alpha', game: 2 },
                { name: 'gamma', game: 3 },
                { name: 'beta', game: 2 }
            ]
        }
    },
    {
        detail: {
            team: [
                { name: 'delta', game: 0 },
                { name: 'echo', game: 1 },
                { name: 'beta', game: 0 },
                { name: 'gamma', game: 2 },
                { name: 'alpha', game: 0 }
            ]
        }
    }
];


const teams = dataset.map(ds => ds.detail.team);
let z = teams.map(element => {
    return element.map(e => {
        let p = {};
        let n = e.name;
        let c = e.game;
        p[n] = c;
        return p;
    });
});

console.log('z', z);

let nt = [];

z.reduce((c, n, i, a) => {
    let z1 = n.map((i) => {
        console.log(i);
        let entries = Object.entries(i);
        return entries.map((e) => {
          return { label: e[0], data: e[1] };
        });
    });
    return z1;
}, [])

desired output:

[
    {
        label: 'alpha',
        data: [1, 2, 0, 0, 2, 0]
    },
    {
        label: 'beta',
        data: [1, 2, 0, 0, 2, 0]
    },
    {
        label: 'gamma',
        data: [1, 2, 0, 1, 3, 2]
    },
    {
        label: 'delta',
        data: [ 1, 2, 0, 0, 0, 0]
    },
    {
        label: 'echo',
        data: [1, 2, 1, 0, 0, 1]
    }
]

I lost somewhere in the array.reduce method to achieve the output.

I am preferably looking for a es6 solution

any help is appreciated.

4 Answers 4

1

So I'm going to leave your dataset the same but lets start from the ground up and create some code to step through your data set and get to the desired output.

First we need to de-nest the data:

dataset.map(d => d.detail.team)

Now that we have teams lets reduce them all to a single array

dataset
  .map(object => object.detail.team)
  .reduce((acc, team) => acc.concat(team))

Okay good now we have one big set of names and games. We can now make this pretty easily into a hash

dataset
  .map(object => object.detail.team)
  .reduce((acc, team) => acc.concat(team))
  .reduce((acc, team) =>{
    acc[team.name] = acc[team.name] || []
    acc[team.name].push(team.game)
    return acc
  }, {})

Now we have a hash of names to games. Calling Object.entries on this hash will give us pairs of lables

Object.entries(
  dataset
    .map(object => object.detail.team)
    .reduce((acc, team) => acc.concat(team))
    .reduce((acc, team) =>{
      acc[team.name] = acc[team.name] || []
      acc[team.name].push(team.game)
      return acc
    }, {})
)

Now we can map over these pairs to construct the final object

Object.entries(
  dataset
    .map(object => object.detail.team)
    .reduce((acc, team) => acc.concat(team), [])
    .reduce((acc, team) =>{
      acc[team.name] = acc[team.name] || []
      acc[team.name].push(team.game)
      return acc
    }, {})
)
  .map(([team, games]) => ({ team, games }))

The real trick now is how many of these steps can be combined?

Well most of them! We can reduce this to looping over each object, referencing manually since we know structure, and then looping over each individual team array and finally constructing our hash.

Object.entries(
  dataset
    .reduce((acc, object) =>{
      object.detail.team.forEach(team =>{
        acc[team.name] = acc[team.name] || []
        acc[team.name].push(team.game)
      })
      return acc
    }, {})
)
  .map(([team, games]) => ({ team, games }))

Extra Notes

Arrow Functions

We used arrow functions in this example to adhere to the request of using ES6 as much as possible. More information on arrow functions can be found on the MDN. Basically though it's another way to declare a function

function test(value){ return console.log(value) }
// same as
let test = value => console.log(value)

function add(a, b){ return a + b)
// same as
let add = (a,b) => a + b

Note the Array.prototype.forEach()

Now you'll notice we used an Array.prototype.forEach() in the combined example to manipulate the accumulator. That sentence should say all we need to there but for clarification for those who might not know, forEach is to be used when you want no return value and only want side effects. In this situation it's faster than attempting to actually return something since we don't want the overhead of discarding a bunch of arrays we've made when the end goal is to only change the way the accumulator looks.

That funky array being passed to a function

Ah yes, destructuring. Again more information can be found on the MDN. Basically it lets us pull values out of Objects or Arrays we know the structure of in advance. Note: Example courtesy of MDN article

var a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20

[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]

({ a, b } = { a: 10, b: 20 });
console.log(a); // 10
console.log(b); // 20


// Stage 3 proposal
({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40});
console.log(a); // 10
console.log(b); // 20
console.log(rest); // {c: 30, d: 40}
Sign up to request clarification or add additional context in comments.

5 Comments

in this .reduce((acc, team) => acc.concat(team)) you have not used 2nd parameter than how does it work? what would be the first value if acc?
The default value of the accumilator in reduce is the first value in the array of no second argument is supplied
but later on 4th blovk you have written .reduce((acc, team) => acc.concat(team), []) this confuse me when to use initail valur and when not to write. will you please create a demo of the solution?
I already have you use an initial value when you need something different than the type supplied in the array or when you need to make sure there are no left over references. In that fourth block I use the initial value because I'll be making a hash object map where I can't have any initial keys or values. So I used a new object as the initial value to make sure the object is empty
this is again something magical .map(([team, games]) => ({ team, games })) Thanks
1

You can use Array.reduce(), to create a map and than use that map to get the desired output.

const dataset = [{detail:{team:[{name:'alpha',game:1},{name:'beta',game:1},{name:'gamma',game:1},{name:'delta',game:1},{name:'echo',game:1}]}},{detail:{team:[{name:'alpha',game:2},{name:'beta',game:2},{name:'echo',game:2},{name:'gamma',game:2},{name:'delta',game:2}]}},{detail:{team:[{name:'echo',game:1},{name:'delta',game:0},{name:'beta',game:0},{name:'gamma',game:0},{name:'alpha',game:0}]}},{detail:{team:[{name:'delta',game:0},{name:'echo',game:0},{name:'beta',game:0},{name:'gamma',game:1},{name:'alpha',game:0}]}},{detail:{team:[{name:'delta',game:0},{name:'echo',game:0},{name:'alpha',game:2},{name:'gamma',game:3},{name:'beta',game:2}]}},{detail:{team:[{name:'delta',game:0},{name:'echo',game:1},{name:'beta',game:0},{name:'gamma',game:2},{name:'alpha',game:0}]}}];
var map = dataset.reduce((a,curr)=>{
    curr.detail.team.forEach((e)=> (a[e.name]= (a[e.name] || [])).push(e.game));
    return a;
}, {});
var result =[];

Object.keys(map).forEach((key)=>{
  result.push({
    "label" : key,
    "data" : map[key]
  });
});

console.log(result);

Comments

1

You can use reduce to make a flat array and then loop over to get the wanted format

const dataset = [{detail:{team:[{name:'alpha',game:1},{name:'beta',game:1},{name:'gamma',game:1},{name:'delta',game:1},{name:'echo',game:1}]}},{detail:{team:[{name:'alpha',game:2},{name:'beta',game:2},{name:'echo',game:2},{name:'gamma',game:2},{name:'delta',game:2}]}},{detail:{team:[{name:'echo',game:1},{name:'delta',game:0},{name:'beta',game:0},{name:'gamma',game:0},{name:'alpha',game:0}]}},{detail:{team:[{name:'delta',game:0},{name:'echo',game:0},{name:'beta',game:0},{name:'gamma',game:1},{name:'alpha',game:0}]}},{detail:{team:[{name:'delta',game:0},{name:'echo',game:0},{name:'alpha',game:2},{name:'gamma',game:3},{name:'beta',game:2}]}},{detail:{team:[{name:'delta',game:0},{name:'echo',game:1},{name:'beta',game:0},{name:'gamma',game:2},{name:'alpha',game:0}]}}];
const flat = dataset.reduce( (a,b) => a.concat(b.detail.team), []);
let result = [];

for (let element of flat) {

  let match = null;

  for (let e  of result) {
    if (e.label === element.name) {
      match = e;
    }
  }

  if (match) {
    match.data.push(element.game)
  }
  else {
    result.push({
      label : element.name,
      data  : [element.game]
    });
  }

}

console.log(result);

Comments

1

Another way: loop through the data set as it is, storing the results in a map dictionary-like object as well as in the array of results to be returned.

const dataset = [{detail:{team:[{name:'alpha',game:1},{name:'beta',game:1},{name:'gamma',game:1},{name:'delta',game:1},{name:'echo',game:1}]}},{detail:{team:[{name:'alpha',game:2},{name:'beta',game:2},{name:'echo',game:2},{name:'gamma',game:2},{name:'delta',game:2}]}},{detail:{team:[{name:'echo',game:1},{name:'delta',game:0},{name:'beta',game:0},{name:'gamma',game:0},{name:'alpha',game:0}]}},{detail:{team:[{name:'delta',game:0},{name:'echo',game:0},{name:'beta',game:0},{name:'gamma',game:1},{name:'alpha',game:0}]}},{detail:{team:[{name:'delta',game:0},{name:'echo',game:0},{name:'alpha',game:2},{name:'gamma',game:3},{name:'beta',game:2}]}},{detail:{team:[{name:'delta',game:0},{name:'echo',game:1},{name:'beta',game:0},{name:'gamma',game:2},{name:'alpha',game:0}]}}];
var result = [],
  map = {};
dataset.forEach(a => {
  a.detail.team.forEach(b => {
    if (!(b.name in map)) {
      map[b.name] = [];
      result.push({
        'label': b.name,
        'data': map[b.name]
      })
    }
    map[b.name].push(b.game);
  });
});
console.log(result);
   

There's not much need to reduce or map any arrays here.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.