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\$
2
  • 1
    \$\begingroup\$ Here's an idea: pastebin.com/T8pqrVZ0 \$\endgroup\$ Commented Aug 22, 2015 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
    Commented Nov 5, 2015 at 8:08

1 Answer 1

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\$
4
  • \$\begingroup\$ Even better, we can use flatMap \$\endgroup\$
    – mpen
    Commented May 21, 2019 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.-
    Commented May 22, 2019 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
    Commented May 23, 2019 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
    Commented May 23, 2019 at 0:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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