3
\$\begingroup\$

This is stripped down from a project I'm working on:

let userFields = {
    id: {
        dbFields: 'id',
    },
    email: {
        dbFields: 'email',
    },
    first_name: {
        dbFields: 'first_name',
    },
    last_name: {
        dbFields: 'last_name',
    },
    name: {
        dbFields: ['first_name', 'last_name'],
        resolve: user => [user.first_name, user.last_name].filter(n => n.length).join(' '),
    }
};

let selectFields = ['name', 'first_name', 'email'];

let dbFields = new Set();
selectFields.forEach(f => {
    if(userFields[f].dbFields) {
        if(userFields[f].dbFields instanceof Array) {
            userFields[f].dbFields.forEach(x => dbFields.add(x));
        } else {
            dbFields.add(userFields[f].dbFields);
        }
    }
});

console.log(Array.from(dbFields)); // [ 'first_name', 'last_name', 'email' ]

I don't like that big selectFields.forEach or the fact that Set doesn't appear to have an addMany method.

Is there any way I can compact this a bit more?

You can run this with babel-node if you need to (npm install -g babel).

\$\endgroup\$
  • 1
    \$\begingroup\$ Here's an idea: pastebin.com/T8pqrVZ0 \$\endgroup\$ – Gabriel Garcia Aug 22 '15 at 23:45
  • \$\begingroup\$ LGTM. I basically don't see a way to make it more compact without getting intricate or doing something kind of strange. Some small changes: jsfiddle.net/66svv9pe \$\endgroup\$ – tiffon Nov 5 '15 at 8:08
1
\$\begingroup\$

Taking advantage of Array​.prototype​.flat() we might compact this a bit.

Basically, we filter all of our fields, making them an array if they are not already, getting out an array of arrays (nested only one level). After that, we can easily flatten it, so we iterate each element and we can just add it to our set.

let userFields = {
    id: {
        dbFields: 'id',
    },
    email: {
        dbFields: 'email',
    },
    first_name: {
        dbFields: 'first_name',
    },
    last_name: {
        dbFields: 'last_name',
    },
    name: {
        dbFields: ['first_name', 'last_name'],
        resolve: user => [user.first_name, user.last_name].filter(n => n.length).join(' '),
    }
};

let selectFields = ['name', 'first_name', 'email'];

let dbFields = new Set();
selectFields.map(key => {
    let field = userFields[key].dbFields;
    return (field instanceof Array) ? field : [field]
  })
  .flat()
  .forEach(v => dbFields.add(v));
console.log(Array.from(dbFields));
  

\$\endgroup\$
  • \$\begingroup\$ Even better, we can use flatMap \$\endgroup\$ – mpen May 21 at 22:17
  • \$\begingroup\$ I would have to review it, I am unsure how it works if not all elements inside the array are arrays \$\endgroup\$ – Gonzalo.- May 22 at 17:01
  • \$\begingroup\$ I tried it. Seems to work well whether or not you do Array.isArray(field) ? field : [field]. That simplifies the loop to: selectFields.flatMap(key => userFields[key].dbFields).forEach(v => dbFields.add(v)); \$\endgroup\$ – mpen May 23 at 0:25
  • \$\begingroup\$ Or even more fun: const dbFields = selectFields.flatMap(key => userFields[key].dbFields).reduce((s,v) => s.add(v), new Set); \$\endgroup\$ – mpen May 23 at 0:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.