0

I have the following

const measures = [
  { "13798494-value": 0.207, readingDate: "26/06/2023" },
  { "4958469-value": 0.211 , readingDate: "26/06/2023" },
  { "13798494-value": 0.214 , readingDate: "27/06/2023" },
  { "4958469-value": 0.123, readingDate: "27/06/2023" }
]

but I need it like this

const measures = [
    { readingDate: "26/06/2023", "13798494-value": 0.207, "4958469-value": 0.211 },
    { readingDate: "27/06/2023", "13798494-value": 0.214, "4958469-value": 0.123 }
]

I've tried the following but I cant get it to work


 const reduceThis = measures?.reduce(
          (acc, item) => {
            const key = Object.keys(item)[0]
            const value = Object.values(item)[0]

            const queryResult = acc.find(
              (qr) => qr?.readingDate === item?.readingDate,
            )

            if (queryResult) {
              queryResult.results.push({ [key]: value })
            } else {
              let newQR = {
                readingDate: item?.readingDate,
                results: [{ [key]: value }],
              }
              acc.push(newQR)
            }

            return acc
          },
          [],
        )

But this comes back as

const measures = [
    { readingDate: "26/06/2023", results: [{"13798494-value": 0.207, "4958469-value": 0.211}] },
    { readingDate: "27/06/2023", results: [{"13798494-value": 0.214, "4958469-value": 0.123}] }
]

So I'm nearly there but cant quite get it.

The format "XXXXXXXX-value" is dynamic and the XXXXXXXX can be anything so we cant directly reference those values.

Thanks

32423hjh32423
  • 3,048
  • 7
  • 44
  • 59
  • Does this answer your question? [Most efficient method to groupby on an array of objects](https://stackoverflow.com/questions/14446511/most-efficient-method-to-groupby-on-an-array-of-objects) – jabaa Jul 10 '23 at 14:37

4 Answers4

1

Try this

const measures = [
  { "13798494-value": 0.207, readingDate: "26/06/2023" },
  { "4958469-value": 0.211, readingDate: "26/06/2023" },
  { "13798494-value": 0.214, readingDate: "27/06/2023" },
  { "4958469-value": 0.123, readingDate: "27/06/2023" }
];

// Group the measures by readingDate
const groupedMeasures = measures.reduce((acc, measure) => {
  const { readingDate, ...rest } = measure;
  if (!acc[readingDate]) {
    acc[readingDate] = { readingDate, ...rest };
  } else {
    Object.assign(acc[readingDate], rest);
  }
  return acc;
}, {});

// Convert the grouped measures object to an array
const sortedMeasures = Object.values(groupedMeasures);

Start reduce with an empty object {}. Get readingDate from current index and check if it already exists in the object. If yes, add the remaining values ...rest from the measures object for the date. If not, add the date as a new key and assign remaining values then. Convert to an array afterwards.

Tabea
  • 95
  • 9
  • @ChrisG start reduce with an empty object {}. Get `readingDate` from current index and check if it already exists in the object. If yes, add the remaining values `...rest` from the `measures` object for the date. If not, add the date as a new key and assign remaining values then. Convert to an array afterwards. – Tabea Jul 10 '23 at 14:54
1

To make it fast use Array::reduce to collect items with the same readingDate in an array and in a map (for further quick access to add additional properties):

const measures = [
  { "13798494-value": 0.207, readingDate: "26/06/2023" },
  { "4958469-value": 0.211 , readingDate: "26/06/2023" },
  { "13798494-value": 0.214 , readingDate: "27/06/2023" },
  { "4958469-value": 0.123, readingDate: "27/06/2023" }
]

  
const mapped = measures.reduce((r, {readingDate, ...props}) => {
  let item = r.map.get(readingDate);
  item ? Object.assign(item, props) :
    r.map.set(readingDate, r.arr[r.arr.length] = {readingDate, ...props});
  return r;
}, {arr: [], map: new Map}).arr;

console.log(mapped);
Alexander Nenashev
  • 8,775
  • 2
  • 6
  • 17
1

You can reduce the array of object to build a new one item by item. As you iterate, if the current object does not exist in the new one, you add it, otherwise, you spread the contents of the current object into the existing one.

const measures = [
    { "13798494-value": 0.207, readingDate: "26/06/2023" },
    { "4958469-value": 0.211 , readingDate: "26/06/2023" },
    { "13798494-value": 0.214 , readingDate: "27/06/2023" },
    { "4958469-value": 0.123, readingDate: "27/06/2023" }
]

const reduced = measures.reduce((acc, cur) => {
    const foundIndex = acc.findIndex(({ readingDate }) => (readingDate === cur.readingDate));
    if (foundIndex > -1)
        acc[foundIndex] = { ...acc[foundIndex], ...cur };
    else
        acc.push(cur);
    return acc;
}, []);

console.log(reduced);
M0nst3R
  • 5,186
  • 1
  • 23
  • 36
1

This could be consolidated but is in my opinion easier to read

let grouped = measures.reduce((acc, cur) => {
  const { readingDate, ...rest } = cur;
  acc[readingDate] ??= { results: [] }; // initialise when needed
  acc[readingDate].results.push(rest); // add
  return acc;
}, {});
grouped = Object.entries(grouped).reduce((acc, [key, value]) => {
  acc.push({ readingDate: key, results: value.results });
  return acc;
}, []);
console.log(grouped)
<script>
const measures = [
  { "13798494-value": 0.207, readingDate: "26/06/2023" },
  { "4958469-value": 0.211 , readingDate: "26/06/2023" },
  { "13798494-value": 0.214 , readingDate: "27/06/2023" },
  { "4958469-value": 0.123, readingDate: "27/06/2023" }
]
</script>
mplungjan
  • 169,008
  • 28
  • 173
  • 236