1

i'm trying to duplicate objects based on two properties that have multiple values differentiated by a comma. For example:

I have an object

const obj = {
  id: 1
  date: "2021"
  tst1: "111, 222"
  tst2: "AAA, BBB"
}

And I would like the result to be an array of 2 objects in this case (because there are 2 values in tst1 OR tst2, these 2 properties will always have the same nr of values differentiated by a comma)

[{
  id: 1,
  date: "2021",
  tst1: "111",
  tst2: "AAA",
},
{
  id: 1,
  date: "2021",
  tst1: "222",
  tst2: "BBB",
}]

What I tried is this:

I created a temporary object

const tempObject = {
      id: obj.id,
      date: obj.date,
}

And then I would split and map the property that has multiple values, like this:

cont newObj = obj.tst1.split(",").map(function(value) {
    let finalObj = {}
    return finalObj = {
        id: tempObject.id,
        date: tempObject.date,
        tst1: value,
    })

And now, the newObj is an array of objects and each object contains a value of tst1. The problem is I still have to do the same for the tst2...

And I was wondering if there is a simpler method to do this...

Thank you!

alexander1911
  • 123
  • 1
  • 9

3 Answers3

1

Not sure if that's what you're searching for, but I tried making a more general use of what you try to do:

const duplicateProperties = obj => {
    const properties = Object.entries(obj);
    let acc = [{}];
    properties.forEach(([key, value]) => {
        if (typeof value === 'string' && value.includes(',')) {
            const values = value.split(',');
            values.forEach((v, i) => {
                if (!acc[i]) {
                    acc[i] = {};
                }
                acc[i][key] = v.trim();
            });
        } else {
            acc.forEach(o => o[key] = value);
        }
    });
    return acc;
};


const obj = {
    id: 1,
    date: '2021',
    tst1: '111, 222',
    tst2: 'AAA, BBB',
};

console.log(duplicateProperties(obj));
Nuro007
  • 157
  • 12
  • Thanks for the reply! I tested this code and it returns an array of objects, but those objects have only those properties that have multiple values differentiated by a comma... It return something like this: [{tst1: "111", tst2:"AAA}, {tst1: "222", tst2: "BBB"}] And I would need for each object to also contain the id and date – alexander1911 Jan 19 '23 at 12:59
  • oohh, my bad, this only returns the properties that are duplicated right? It should include the non-duplicated ones too, correct? – Nuro007 Jan 19 '23 at 13:09
  • Yes, it should return also the non-duplicated ones – alexander1911 Jan 19 '23 at 13:18
  • 1
    You just need to initialize objects in the accumulator with the obj. `if (!acc[i]) { acc[i] = {...obj}; }` – pilchard Jan 19 '23 at 13:30
  • thanks @pilchard, also alexander1911, I;ve edited my answer. – Nuro007 Jan 19 '23 at 15:45
1

Here is an example that accepts an array of duplicate keys to differentiate. It first maps them to arrays of entries by splitting on ',' and then trimming the entries, then zips them by index to create sub-arrays of each specified property, finally it returns a result of the original object spread against an Object.fromEntries of the zipped properties.

const mapDuplicateProps = (obj, props) => {
  const splitProps = props.map((p) =>
    obj[p].split(',').map((s) => [p, s.trim()])
  );
  // [ [[ 'tst1', '111' ], [ 'tst1', '222' ]], [[ 'tst2', 'AAA' ], [ 'tst2', 'BBB' ]] ]

  const dupeEntries = splitProps[0].map((_, i) => splitProps.map((p) => p[i]));
  // [ [[ 'tst1', '111' ], [ 'tst2', 'AAA' ]], [[ 'tst1', '222' ], [ 'tst2', 'BBB' ]] ]

  return dupeEntries.map((d) => ({ ...obj, ...Object.fromEntries(d) }));
};

const obj = {
  id: 1,
  date: '2021',
  tst1: '111, 222',
  tst2: 'AAA, BBB',
};

console.log(mapDuplicateProps(obj, ['tst1', 'tst2']));
pilchard
  • 12,414
  • 5
  • 11
  • 23
1

You could start by determining the length of the result using Math.max(), String.split() etc.

Then you'd create an Array using Array.from(), returning the correct object for each value of the output index.

const obj = {
  id: 1,
  date: "2021",
  tst1: "111, 222",
  tst2: "AAA, BBB",
}

// Determine the length of our output array...
const length = Math.max(...Object.values(obj).map(s => (s + '').split(',').length))

// Map the object using the relevant index...
const result = Array.from({ length }, (_, idx) => { 
    return Object.fromEntries(Object.entries(obj).map(([key, value]) => {
        const a = (value + '').split(/,\s*/);
        return [key, a.length > 1 ? a[idx] : value ]
    }))
})

console.log(result)
.as-console-wrapper { max-height: 100% !important; }
Terry Lennox
  • 29,471
  • 5
  • 28
  • 40