ishikawa
ishikawa

Reputation: 21

How to create an array from an array of objects by same key

I have an array of objects.
I want to merge the objects into a single array by same key. At that time, I also want to include other value in the array together.
It doesn't matter whether the merged array is an array or an object.

Current array:

[
  {
    "datetime": "2022-01-10",
    "a": 0.5,
    "b": 80.6,
    "c": 1002.2
  },
  {
    "datetime": "2022-01-11",
    "a": 0.7,
    "b": 80.4,
    "c": 1002.4
  },
  {
    "datetime": "2022-01-12",
    "a": 0.4,
    "b": 80.2,
    "c": 1002.3
  }
]

Expected result:

[
  [
    ["2022-01-10", 0.5], ["2022-01-11", 0.7], ["2022-01-12", 0.4]
  ],
  [
    ["2022-01-10", 80.6], ["2022-01-11", 80.4], ["2022-01-12", 1002.4]
  ],
  [
    ["2022-01-10", 1002.2], ["2022-01-11", 1002.4], ["2022-01-12", 1002.3]
  ]
]

or

{
  "a": [
    ["2022-01-10", 0.5], ["2022-01-11", 0.7], ["2022-01-12", 0.4]
  ],
  "b": [
    ["2022-01-10", 80.6], ["2022-01-11", 80.4], ["2022-01-12", 1002.4]
  ],
  "c": [
    ["2022-01-10", 1002.2], ["2022-01-11", 1002.4], ["2022-01-12", 1002.3]
  ]
}

I use forEach() and it works.
But I want to know if there are other ways.

const foo = [[], [], []];
json.forEach((item) => {
  const [a, b, c] = foo;
  a.push([item.datetime, item.a]);
  b.push([item.datetime, item.b]);
  c.push([item.datetime, item.c]);
});

Upvotes: 2

Views: 140

Answers (5)

Ronak
Ronak

Reputation: 419

You can use reduce function where the initial value will be an empty object. after that, you can check if that object contains that particular key or not and push the data accordingly

a = [
  {
    datetime: "2022-01-10",
    a: 0.5,
    b: 80.6,
    c: 1002.2,
  },
  {
    datetime: "2022-01-11",
    a: 0.7,
    b: 80.4,
    c: 1002.4,
  },
  {
    datetime: "2022-01-12",
    a: 0.4,
    b: 80.2,
    c: 1002.3,
  },
];

const solution = (key) => {
  return a.reduce((acc, { [key]: keyValue, ...next }) => {
    Object.entries(next).forEach(([dataKey, dataValue]) => {
      (acc[dataKey] ??= []).push([keyValue, dataValue]);
    });
    return acc;
  }, {});
};

console.log('Solution 1: ',Object.values(solution("datetime")));
console.log('Solution 2: ',solution("datetime"));

Upvotes: 1

Peter Seliger
Peter Seliger

Reputation: 13376

As for generic solutions (only the datetime property of each item needs to be known, thus the solutions are agnostic to all other properties) to both of the OP's use cases,

  • the array of arrays where the nested array items are tuples of distinct datetime values and values of same item keys
  • and the object of arrays where the arrays are the same but get referred to by keys which are distinct from datetime,

one easily could use the same reduce based approach only that

  • for the latter result (object based key specific array of arrays) one passes an object as initial value and creates and aggregates the key specific nested arrays upon the currently processed key of each item's rest-property data-entries,

  • whereas for the former result (array of arrays) the initial value is an array where one needs to create and/or access each key specific inner array by the current index of each of the rest-data's values.

const sampleData = [{
  datetime: "2022-01-10",
  a: 0.5,
  b: 80.6,
  c: 1002.2,
}, {
  datetime: "2022-01-11",
  a: 0.7,
  b: 80.4,
  c: 1002.4,
}, {
  datetime: "2022-01-12",
  a: 0.4,
  b: 80.2,
  c: 1002.3,
}];

console.log(

  sampleData
    .reduce((result, { datetime, ...rest }) => {
      Object
        .values(rest)
        .forEach((value, idx) =>
          (result[idx] ??= []).push([datetime, value])
        );
        return result;
    }, [])
);
console.log(

  sampleData
    .reduce((result, { datetime, ...rest }) => {
      Object
        .entries(rest)
        .forEach(([key, value]) =>
          (result[key] ??= []).push([datetime, value])
        );
        return result;
    }, {})
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

In case the key (insertion) order of the original array items can not be guarantied amongst all items, one should use the key-specific second solution, where one would pass the created object to Object.values in order to get an array of arrays ...

const sampleData = [{
  datetime: "2022-01-10",
  a: 0.5,
  b: 80.6,
  c: 1002.2,
}, {
  datetime: "2022-01-11",
  a: 0.7,
  b: 80.4,
  c: 1002.4,
}, {
  datetime: "2022-01-12",
  a: 0.4,
  b: 80.2,
  c: 1002.3,
}];

console.log(

  Object
    .values(
      sampleData
        .reduce((result, { datetime, ...rest }) => {
          Object
            .entries(rest)
            .forEach(([key, value]) =>
              (result[key] ??= []).push([datetime, value])
            );
            return result;
        }, {})
    )
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

Upvotes: 1

Skkk
Skkk

Reputation: 1

See this it uses map and then returns an array just like your ist

const data = [{
  datetime: "2022-01-10",
  a: 0.5,
  b: 80.6,
  c: 1002.2,
}, {
  datetime: "2022-01-11",
  a: 0.7,
  b: 80.4,
  c: 1002.4,
}, {
  datetime: "2022-01-12",
  a: 0.4,
  b: 80.2,
  c: 1002.3,
}];

const res = data.map((m ,_) => [
  [m.datetime,m.a],
  [m.datetime,m.b],
  [m.datetime,m.c],
]);
console.log({ res });

Or 2nd method because of comments

const data = [{
  datetime: "2022-01-10",
  a: 0.5,
  b: 80.6,
  c: 1002.2,
}, {
  datetime: "2022-01-11",
  a: 0.7,
  b: 80.4,
  c: 1002.4,
}, {
  datetime: "2022-01-12",
  a: 0.4,
  b: 80.2,
  c: 1002.3,
}];

const res = ["a","b","c"].map(key => data.map(obj => [
  obj.datetime,
  obj[key],
]));
console.log({ res });

Upvotes: 0

Ahmad
Ahmad

Reputation: 1479

const Json = [
    {
        "datetime": "2022-01-10",
        "a": 0.5,
        "b": 80.6,
        "c": 1002.2
    },
    {
        "datetime": "2022-01-11",
        "a": 0.7,
        "b": 80.4,
        "c": 1002.4
    },
    {
        "datetime": "2022-01-12",
        "a": 0.4,
        "b": 80.2,
        "c": 1002.3
    }
]

const func = (arr, i) => {
    let result = [];
    const constants = ["a", "b", "c"];
    for (let index = 0; index < arr.length; index++) {
        result.push([arr[index].datetime, arr[index][`${constants[i]}`]]);
    }
    return result;
}

const result = Json.map((d, i) => {
    return func(Json, i);
});

console.log(result)

Upvotes: 0

Talha Fayyaz
Talha Fayyaz

Reputation: 509

you can use javascript reduce to optimize this:

const data = temp.reduce((acc,{a,b,c,datetime})=>{
  const [first,second,third] = acc;
  first.push([datetime, a]);
  second.push([datetime, b]);
  third.push([datetime, c]);
  return acc;
},[[],[],[]])

Upvotes: 0

Related Questions