Luke Vanzweden
Luke Vanzweden

Reputation: 646

What is the best way to simplify Objects in JavaScript (perferably using Jquery)

I have an Object that looks like this:

var dataSource = [{
    date: new Date(1994, 2, 2),
    name: "a",
    l: 24.00,
    h: 25.00,
    o: 25.00,
    c: 24.875
}, {
    date: new Date(1994, 2, 2),
    name: "a",
    l: 23.625,
    h: 25.125,
    o: 24.00,
    c: 24.875
}, {
    date: new Date(1994, 2, 3),
    name: "a",
    l: 26.25,
    h: 28.25,
    o: 26.75,
    c: 27.00
}, {
    date: new Date(1994, 2, 4),
    name: "c",
    l: 26.50,
    h: 27.875,
    o: 26.875,
    c: 27.25
}, { 

and so on... I want to combine entries by their date, meaning if two datapoints have the same date and name, I want to add them together so the output would be:

var dataSource = [{
    date: new Date(1994, 2, 2),
    name: "a",
    l: 47.625,
    h: 50.125,
    o: 49.00,
    c: 49.75
}, {
    date: new Date(1994, 2, 3),
    name: "a",
    l: 26.25,
    h: 28.25,
    o: 26.75,
    c: 27.00
}, {
    date: new Date(1994, 2, 4),
    name: "c",
    l: 26.50,
    h: 27.875,
    o: 26.875,
    c: 27.25
}, { 

Right now the best way I can think of doing this would be a for loop that runs until the size of the object doesnt change any more. Is there a better way of doing this, possibly a jquery function similar to grep that could do this?

Upvotes: 0

Views: 162

Answers (4)

Mister Jojo
Mister Jojo

Reputation: 22265

this way

const data = 
  [ { date: new Date(1994, 2, 2), name: "a"
    , l: 24.00, h: 25.00, o: 25.00, c: 24.875
    } 
  , { date: new Date(1994, 2, 2), name: "a"
    , l: 23.625, h: 25.125, o: 24.00, c: 24.875
    } 
  , { date: new Date(1994, 2, 3), name: "a"
    , l: 26.25, h: 28.25, o: 26.75, c: 27.00
    } 
  , { date: new Date(1994, 2, 4), name: "c"
    , l: 26.50, h: 27.875, o: 26.875, c: 27.25
    } 
  ] 
       
const Result = data.reduce((acc,c)=>
  {
  let same = acc.find(x=>x.date.getTime()===c.date.getTime()
                         && x.name===c.name)
  if(!same)
    acc.push({...c})
  else
    {
    same.l += c.l
    same.h += c.h
    same.o += c.o
    same.c += c.c  
    }
  return acc
  }, [])

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

Upvotes: 0

pilchard
pilchard

Reputation: 12911

You can use a reduce() call grouping elements by a compound key made of the the date concatenated with the name (o.date.valueOf() + o.name), summing the relevant keys and then calling Object.values() on the result to return an array of the merged objects.

const dataSource = [{ date: new Date(1994, 2, 2), name: "a", l: 24.00, h: 25.00, o: 25.00, c: 24.875 }, { date: new Date(1994, 2, 2), name: "a", l: 23.625, h: 25.125, o: 24.00, c: 24.875 }, { date: new Date(1994, 2, 3), name: "a", l: 26.25, h: 28.25, o: 26.75, c: 27.00 }, { date: new Date(1994, 2, 4), name: "c", l: 26.50, h: 27.875, o: 26.875, c: 27.25 }];

const
  sumKeys = (a, b) => ['l', 'h', 'o', 'c'].forEach(k => a[k] += b[k]),
  grouped = Object.values(
    dataSource.reduce((a, o) => {
      const entry = (a[o.date.valueOf() + o.name] ??= { name: o.name, date: o.date.valueOf(), l: 0, h: 0, o: 0, c: 0 });
      sumKeys(entry, o);
      return a;
    }, {}));

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

or if you need to avoid logical nullish assignment (??=) for compatibility...

const dataSource = [{ date: new Date(1994, 2, 2), name: "a", l: 24.00, h: 25.00, o: 25.00, c: 24.875 }, { date: new Date(1994, 2, 2), name: "a", l: 23.625, h: 25.125, o: 24.00, c: 24.875 }, { date: new Date(1994, 2, 3), name: "a", l: 26.25, h: 28.25, o: 26.75, c: 27.00 }, { date: new Date(1994, 2, 4), name: "c", l: 26.50, h: 27.875, o: 26.875, c: 27.25 }];

const
  sumKeys = (a, b) => ['l', 'h', 'o', 'c'].forEach(k => a[k] += b[k]),
  grouped = Object.values(
    dataSource.reduce((a, o) => {
      const entry = (a[o.date.valueOf() + o.name] = a[o.date.valueOf() + o.name] || { name: o.name, date: o.date.valueOf(), l: 0, h: 0, o: 0, c: 0 });
      sumKeys(entry, o);
      return a;
    }, {}));

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

Upvotes: 1

linchong
linchong

Reputation: 483

  let arr = dataSource.reduce((cur, next) => {
    const flag = cur.some(ele => {
      return ele.date.valueOf() === next.date.valueOf() && ele.name === next.name
    })
    if(!flag) {
      cur.push(next)
    }
    return cur;
  }, [])
  console.log(arr)

Upvotes: 0

D. Seah
D. Seah

Reputation: 4592

you can track the date and name in a mapper first

var dataSource = [{
  date: new Date(1994, 2, 2),
  name: "a",
  l: 24.00,
  h: 25.00,
  o: 25.00,
  c: 24.875
}, {
  date: new Date(1994, 2, 2),
  name: "a",
  l: 23.625,
  h: 25.125,
  o: 24.00,
  c: 24.875
}, {
  date: new Date(1994, 2, 3),
  name: "a",
  l: 26.25,
  h: 28.25,
  o: 26.75,
  c: 27.00
}, {
  date: new Date(1994, 2, 4),
  name: "c",
  l: 26.50,
  h: 27.875,
  o: 26.875,
  c: 27.25
}];

const mapper = dataSource.reduce((acc, cur) => {
  acc[cur.date] = acc[cur.date] || {};
  acc[cur.date][cur.name] = acc[cur.date][cur.name] || {};

  ["l", "h", "o", "c"].forEach(k => {
    acc[cur.date][cur.name][k] = (acc[cur.date][cur.name][k] || 0) + cur[k];
  });

  return acc;
}, {});

const result = [];

Object.keys(mapper).forEach(d => {
  Object.keys(mapper[d]).forEach(name => {
    const item = mapper[d][name];
    result.push({
      date: d,
      name,
      l: item.l,
      h: item.h,
      o: item.o,
      c: item.c,
    });
  });
});

console.log(result);

Upvotes: 0

Related Questions