How to define an array with conditional elements?

Viewed 103302

How can I define conditional array elements? I want to do something like this:

const cond = true;
const myArr = ["foo", cond && "bar"];

This works as expected and results in ["foo", "bar"] but if I set cond to false, I get the following result: ["foo", false]

How can I define an array with a conditional element?

11 Answers

I'd do this

[
  true && 'one',
  false && 'two',
  1 === 1 && 'three',
  1 + 1 === 9 && 'four'
].filter(Boolean) // ['one', 'three']

Note that this will also remove falsy values, such as empty strings.

const cond = false;
const myArr = ["foo", cond ? "bar" : null].filter(Boolean);

console.log(myArr)

Will result in ["foo"]

Add elements conditionally

/**
 * Add item to array conditionally.
 * @param {boolean} condition
 * @param {*} value new item or array of new items
 * @param {boolean} multiple use value as array of new items (for future)
 * @returns {array} array to spread
 * @example [ ...arrayAddConditionally(true, 'foo'), ...arrayAddConditionally(false, 'bar'), ...arrayAddConditionally(true, [1, 2, 3]), ...arrayAddConditionally(true, [4, 5, 6], true) ] // ['foo', [1, 2, 3], 4, 5, 6]
 */
export const arrayAddConditionally = (condition, value, multiple) => (
    condition
        ? multiple ? value : [value]
        : []
);

Create array with conditional elements


/**
 * Create array with conditional elements
 * @typedef {[condition: boolean, value: any, multiple: boolean]} ConditionalElement
 * @param {(ConditionalElement|*)[]} map non-array element will be added as it is, array element must allways be conditional
 * @returns {array} new array
 * @example createArrayConditionally([[true, 'foo'], [false, 'baz'], [true, [1, 2, 3]], [true, [4, 5, 6], true], {}]) // ['foo', [1,2,3], 4, 5, 6, {}]
 */
export const createArrayConditionally = (map) => (
    map.reduce((newArray, item) => {
        // add non-conditional as it is
        if (!Array.isArray(item)) {
            newArray.push(item);
        } else {
            const [condition, value, multiple] = item;
            // if multiple use value as array of new items
            if (condition) newArray.push[multiple ? 'apply' : 'call'](newArray, value);
        }
        return newArray;
    }, [])
);

This is an alternative to Jordan Enev's answer if you don't care too much about performance and it feels like you want to learn more about Javascript :)

So, if you want to do this, but without the false/undefined/null element

['foo', true && 'bar', null && 'baz']; // ['foo', 'bar', null]

You can do it like this:

['foo', true && 'bar', ...Object.values({ ...(null && ['baz']) })]; // ['foo', 'bar']

Finally, the positive condition will work as expected:

['foo', true && 'bar', ...Object.values({ ...(true && ['baz']) })]; // ['foo', 'bar', 'baz']

Bonus: if you want to add a thing to an array, but the thing can be falsy and then you don't want it in there, without doing a 2nd operation, here's a way to do it:

const foo = 1; // 1
const bar = (() => 'expensive result that turns out falsy for bar' && false)(); // false
const baz = (() => 'expensive result for baz')(); // 'expensive result'
const conditionalArrayWrapperFor = i => i ? [i] : [];
// tip: you can always inline conditionalWrapper if you only execute it once
// for instance, if you're using this inside a reduce call
[foo, ...conditionalArrayWrapperFor(bar), ...conditionalArrayWrapperFor(baz)] // [1, 'expensive result for baz']

if you are using es6, I would suggest

let array = [ "bike", "car", name === "van" ? "van" : null, "bus", "truck", ].filter(Boolean);

This array will only contain value "van" if name equals "van", otherwise it will be discarded.

Related