15
\$\begingroup\$

Using the array.filter function, I can efficiently pull out all elements that do or do not meet a condition:

let large = [12, 5, 8, 130, 44].filter((x) => x > 10);
let small = [12, 5, 8, 130, 44].filter((x) => !(x > 10));

However, in the example above, I'm iterating over the array twice and performing the same test each time. Is there a simple way to generate both 'large' and 'small' in a single pass over the array? In particular, if the callback to evaluate whether an element should be kept is expensive, I'd like to avoid calling it twice.

\$\endgroup\$
12
\$\begingroup\$

Using TypeScript/ECMAScript 6 syntax it can be achieved this way. I am not sure whether it's more or less elegant compared to the original variant, but

  1. It does the job;
  2. Requires only one run;
  3. Can be further chained with map () or other functions.

const [small, large] =                             // Use "deconstruction" style assignment
  [12, 5, 8, 130, 44]
    .reduce((result, element) => {
      result[element <= 10 ? 0 : 1].push(element); // Determine and push to small/large arr
      return result;
    },
    [[], []]);                                     // Default small/large arrays are empty

More options can be found in various StackOverflow questions.

\$\endgroup\$
7
\$\begingroup\$

Anything wrong with the naive ways?

let large = [];
let small = [];

array.forEach((x) => (x > 10 ? large : small).push(x));

// or
for(const x of array){
    (x > 10 ? large : small).push(x);
}
\$\endgroup\$
  • \$\begingroup\$ Why map instead of forEach? \$\endgroup\$ – xehpuk Feb 15 '18 at 20:22
  • \$\begingroup\$ @xehpuk you are right, forEach would be better here. Updated the answer. \$\endgroup\$ – Qtax Feb 19 '18 at 10:27
2
\$\begingroup\$

The existing answers do not seem to address the callback. One way to include it could be:

const partition = (ary, callback) =>
  ary.reduce((acc, e) => {
    acc[callback(e) ? 0 : 1].push(e)
    return acc
  }, [[], []])

and using it like:

let [large, small] = partition([12, 5, 8, 130, 44], (x => x > 10))
\$\endgroup\$
  • \$\begingroup\$ While I think calling a predicate in partition function a "callback" is a bit vague, it's actually a decent solution that you posted. 👍 \$\endgroup\$ – rishat Feb 19 '18 at 15:13
  • \$\begingroup\$ @RishatMuhametshin nomenclature was from OP \$\endgroup\$ – morbusg Feb 19 '18 at 15:16
  • \$\begingroup\$ Rereading it, I'm a bit surprised that I used the term "callback." In fact, I think the code that prompted me to ask this question involved an array of promises, so "callback" was a particularly inopportune way to describe the predicate. \$\endgroup\$ – Max Rosett Feb 19 '18 at 19:12
  • \$\begingroup\$ Usually you'd go with predicate as the name. \$\endgroup\$ – Christian Ivicevic Aug 23 at 14:33

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.