2

Just wondering if it's possible to use an array function (like filter) to return both the negative and the positive outcomes of the statement at the same time using destructuring.

Something like the following:

let {truthys, falsys} = arr.filter(a => {
   return //magical statement that returns truthy's and falsy's?
}); 

instead of:

let truthys = arr.filter(item => item.isTruthy);
let falsys = arr.filter(item => !item.isTruthy);

So something of a shorthand-way of doing the latter. Can't seem to find anything about this anywhere so it might not be possible at all. Thanks!

5
  • 2
    You could use .reduce() to create an object with two arrays. Commented Jun 11, 2021 at 15:04
  • .filter() returns one array of values. Doesn't make much sense to destructure it, if you pass a predicate. What you can do is group by the predicate result and return an object with { "true" : /* items that passed the predicate test */, "false": /* items that did not pass the predicate test */ } and then destructure as const {true: truthys, false: falsys} = groupedValues Commented Jun 11, 2021 at 15:07
  • Thanks! Will give both a try :) Commented Jun 11, 2021 at 15:11
  • 1
    See georg's partition implementation here it's essentially what you need. You'd call it like parition(arr, x => !!x) (or parition(arr, Boolean) if you wish). That's partitioning into an array with indexes 1 and 0 but the approach is the same if you want to partition into an object with keys true and false. I personally prefer the latter because it's a bit clearer that result.true is the result of everything where the condition returned true but ultimately doesn't matter much. Commented Jun 11, 2021 at 15:22
  • 1
    const [thruthys, falsys] = partition(arr, item => item.isTruthy) with an appropriate helper function (see the duplicates) is the standard approach. If you already have a groupBy helper, such as lodash's one, you can also use const {true: truthys, false: falsys} = _.groupBy(arr, item => !!item.isTruthy). Commented Jun 11, 2021 at 16:11

3 Answers 3

0

Your idea can never work as written because the return from filter is necessarily an array, not a structure. If you don't mind just finding one value, this variation works:

{ a, b } = [ { a: 'yyy', b: 'yzz' }, { a: 'aww', b: 'azz' } ].find(e => e.a.startsWith('y'))

> a
'yyy'
> b
'yzz'

But looking more closely I see What You Actually Wanted, so perhaps the most straightforward is:

const a = [ '', ' hello ', ' ', false, [], [0], [''], [' '], null, undefined, new Array(), 0, 1, -1 ]
const { truthies, falsies } = { truthies: a.filter(e => !!e), falsies: a.filter(e => !e) }
console.log(`truthies: ${JSON.stringify(truthies)}\nfalsies: ${JSON.stringify(falsies)}`)

With the result:

{
  truthies: [ ' hello ', ' ', [], [ 0 ], [ '' ], [ ' ' ], [], 1, -1 ],
  falsies: [ '', false, null, undefined, 0 ]
}

EDIT

Inspired by keeping just one filter pass, it's not so pretty, but one can do:

const a = [ '', ' hello ', ' ', false, [], [0], [''], [' '], null, undefined, new Array(), 0, 1, -1 ]
const false_temp = []
const { truthies, falsies } = { truthies: a.filter(e => !!e || (false_temp.push(e) && false)), falsies: false_temp }
console.log(`truthies: ${JSON.stringify(truthies)}\nfalsies: ${JSON.stringify(falsies)}`)

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

1 Comment

Just some fun: 0 is falsish but new Number(0) is truthish but Number(0) is falsish.
-1

You can use .reduce for it:

const getTruthysAndFalsys = (array) => {
  return array.reduce(
    ({ truthys, falsys }, item) => {
      const isTruthy = item.isTruthy

      return {
        truthys: [
          ...truthys,
          ...(isTruthy ? [item] : []),
        ],
        falsys: [
          ...falsys,
          ...(!isTruthy ? [item] : []),
        ],
      }
    },
    { truthys: [], falsys: [] }
  )
}

const array = [
  { name: 'Item 1', isTruthy: true },
  { name: 'Item 2', isTruthy: true },
  { name: 'Item 3', isTruthy: false },
  { name: 'Item 4', isTruthy: true },
  { name: 'Item 4', isTruthy: false },
]


getTruthysAndFalsys(array)
// { 
//   truthys: [ 
//     { name: 'Item 1', isTruthy: true }, 
//     { name: 'Item 2', isTruthy: true }, 
//     { name: 'Item 4', isTruthy: true }, 
//   ], 
//   falsys: [ 
//     { name: 'Item 3', isTruthy: false }, 
//     { name: 'Item 4', isTruthy: false },
//   ],
// } 

Comments

-1

As @Pointy suggested you can avoid filtering two times by dividing the elements into two arrays with Array.prototype.reduce() like this:

const input = [1, 0, true, false, "", "foo"];

const [truthies, falsies] = input.reduce(
  ([truthies, falsies], cur) =>
    !cur ? [truthies, [...falsies, cur]] : [[...truthies, cur], falsies],
  [[], []]
);

console.log(truthies, falsies);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.