2

I have an array containing objects. Now I want to slice the array to a new object containing only those objects matching a certain property name and grouped by this property name. The thing is that I also have properties names that are different between them. The names and ID's repeat through the array of objects, but inside the new object, it should contain the ID and the name only once.

The original array looks like this:

let personArray = [
    {
        id_dentist: 1,
        dentist_name: 'John',
        id_secretary: 6,
        secretary_name: 'Paul',
        id_security: 3,
        security_name: 'Carl'
    },
    {
        id_dentist: 2,
        dentist_name: 'Lisa',
        id_secretary: 9,
        secretary_name: 'Beth',
        id_security: 5,
        security_name: 'Monica'
    },
    {
        id_dentist: 1,
        dentist_name: 'John',
        id_secretary: 6,
        secretary_name: 'Paul',
        id_security: 3,
        security_name: 'Carl'
    }
];

The new object should look like this:

let personObject = {
    dentist: [
        { id_dentist: 1, dentist_name: 'John' },
        { id_dentist: 2, dentist_name: 'Lisa' },
    ],
    secretary: [
        { id_secretary: 6, secretary_name: 'Paul' },
        { id_secretary: 9, secreatary_name: 'Beth' },
    ],
    security: [
        { id_security: 3, security_name: 'Carl' },
        { id_security: 5, security_name: 'Monica' }
    ]
};

I appreciate the help.

As requested, I tried using reduce() and filter(), but I was not able to make them to split. Here is the code:

const obj = personArray.reduce((acc, cur) => {
    const key = Object.keys(cur).filter(f => /^id_/.test(f))[0].split('_')[1];
    if (!acc[key]) acc[key] = [];
    acc[key].push(cur);
    return acc;
}, {});

console.log(obj);

About the strange data structure, I am getting those data from a database with a SELECT SQL syntax.

7
  • This seems like a very strange data structure. Why are all these different jobs mixed into the same objects? Commented Jun 23, 2022 at 17:19
  • I updated the question to fit your criteria. Thanks for the help. Commented Jun 23, 2022 at 17:37
  • It will almost certainly be easier if you use ordinary for loops. Once you get that working, you can try to refactor it into reduce. Commented Jun 23, 2022 at 17:39
  • That was my first approach, but still I could not make it work. I guess I will just keep trying. I appreciate your time replying. Commented Jun 23, 2022 at 17:45
  • key is an array. You're never looping over it to find the XXX_name properties that should be combined with id_XXX. Commented Jun 23, 2022 at 17:48

3 Answers 3

3

Here you go, This can be enhance further

let personArray = [{"id_dentist":1,"dentist_name":"John","id_secretary":6,"secretary_name":"Paul","id_security":3,"security_name":"Carl"},{"id_dentist":2,"dentist_name":"Lisa","id_secretary":9,"secretary_name":"Beth","id_security":5,"security_name":"Monica"},{"id_dentist":1,"dentist_name":"John","id_secretary":6,"secretary_name":"Paul","id_security":3,"security_name":"Carl"}];

const personObject = { dentist: [], secretary: [], security: [] };
const isExist = (arr, id, key) => arr.find(x => x[key] === id);


personArray.reduce((personObj, person) => {
  
  const isDentistExists = isExist(personObj.dentist, person.id_dentist, 'id_dentist');
  
  if (!isDentistExists) {
    personObj.dentist.push({
      id_dentist: person.id_dentist,
      dentist_name: person.dentist_name
    });
  }
  
  const isSecretaryExists = isExist(personObj.secretary, person.id_secretary, 'id_secretary');
  
  if (!isSecretaryExists) {
    personObj.secretary.push({
      id_secretary: person.id_secretary,
      secretary_name: person.secretary_name
    });
  }
  
  const isSecurityExists = isExist(personObj.security, person.id_security, 'id_security');
  
  if (!isSecurityExists) {
    personObj.security.push({
      id_security: person.id_security,
      security_name: person.security_name
    });
  }
  
  return personObj;
}, personObject);

console.log(personObject);

Sign up to request clarification or add additional context in comments.

1 Comment

though pretty basic and straightforward, I'd say it does the job so it's worth picking up.
1

This is not a trivial algorithm. Here is a [mostly] functional implementation that handles an arbitrary number of ids and names

let personArray = [
  {
    id_dentist: 1,
    dentist_name: 'John',
    id_secretary: 6,
    secretary_name: 'Paul',
    id_security: 3,
    security_name: 'Carl',
  },
  {
    id_dentist: 2,
    dentist_name: 'Lisa',
    id_secretary: 9,
    secretary_name: 'Beth',
    id_security: 5,
    security_name: 'Monica',
  },
  {
    id_dentist: 1,
    dentist_name: 'John',
    id_secretary: 6,
    secretary_name: 'Paul',
    id_security: 3,
    security_name: 'Carl',
  },
]

const parsed = Object.fromEntries(
  Object.keys(personArray[0])
    .filter(key => key.startsWith('id_'))
    .map(id => {
      const uniqIds = [...new Set(personArray.map(person => person[id]))]
      const [, name] = id.split('_')
      const matchingPeople = uniqIds.map(uniqId => {
        return personArray.find(person => uniqId === person[id])
      })
      return matchingPeople.map(person => ({
        [id]: person[id],
        [`${name}_name`]: person[`${name}_name`],
      }))
    })
    .filter(entry => entry.length > 0)
    .map(groupedPeople => {
      const [name] = Object.keys(groupedPeople[0])
        .find(key => key.includes('_name'))
        .split('_')
      return [name, groupedPeople]
    })
)
console.log(parsed)

Comments

0

I probably went along a similar path as @Andrew did and, yes, I admit too, that this was not really trivial.

It might be a better idea to change your SQL selection in order to avoid receiving redundant data that makes these lengthy conversions necessary.

const arr = [
{
    id_dentist: 1,
    dentist_name: 'John',
    id_secretary: 6,
    secretary_name: 'Paul',
    id_security: 3,
    security_name: 'Carl'
},
{
    id_dentist: 2,
    dentist_name: 'Lisa',
    id_secretary: 9,
    secretary_name: 'Beth',
    id_security: 5,
    security_name: 'Monica'
},
{
    id_dentist: 1,
    dentist_name: 'John',
    id_secretary: 6,
    secretary_name: 'Paul',
    id_security: 3,
    security_name: 'Carl'
}
], types=Object.keys(arr[0]).reduce((a,c,k)=>{
 k=c.match(/id_(.*)/);
 if(k) a.push(k[1]);
 return a;
},[]);

const res=Object.entries(arr.reduce((a,c)=>{
 types.forEach((t,id)=>{
  id="id_"+t;
  a[t+":"+c[id]]={[id]:c[id],[t+"_name"]:c[t+"_name"]}
 });
 return a;
},{})).reduce((a,[k,o],n)=>{
 [n]=k.split(":");
 (a[n]=a[n]||[]).push(o)
 return a;
},{});

console.log(res);

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.