Node.js: Combining forEach() with early returns












3















My Problem



The ESLint airbnb policy disallows for...of loop iterations, and prefers forEach((element) => { code });. However, inner returns from that loop are swallowed - they are considered returns of the anonymous function rather than the function that embraces the loop.



Code



Original



Works, but breaks eslint-config-airbnb.






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator1() {
const wordlist = ;
for (const word of words) {
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
}
return wordlist;
}

console.log(NestedIterator1());





Alternative 1: Iterating array indices



Works, but the style is outdated and I have to manually assign values by indices.






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;


function NestedIterator2() {
const wordlist = ;
for (let i = 0; i < words.length; i += 1) {
const word = words[i];
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
}
return wordlist;
}


console.log(NestedIterator2());





Alternative 2: Using forEach



Adheres to the style guide, but does not work - the inner returns are considered returns from the anonymous function, rather than the NestedIterator3.






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator3() {
const wordlist = ;
words.forEach((word) => {
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
});
return wordlist;
}

console.log(NestedIterator3());





My Question



How can a function iterate over an array while allowing early returns and avoiding indices and for..of iterations?










share|improve this question


















  • 3





    Well is it really necessary? I defer to the actual reason in the style guide: "Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects.". Whilst I agree that avoiding mutability is grand, saying that for..in or for..of is prone to breaking that is a bit of a stretch. Therefore the rule seems questionable and probably should be overridden

    – Neil Lunn
    Nov 25 '18 at 10:34











  • throwing exception inside of forEach callback with try .. catch would work like break but I believe it'd be more confusing than eslint warning or per-file suppressing the rule

    – skyboyer
    Nov 25 '18 at 10:39






  • 1





    @skyboyer Agree. It's not exactly a "unique" question and has certainly been asked before Short circuit Array.forEach like calling break. I'd rather the OP generally acknowledge the duplicate for themselves. Certainly can't see how there would be a completely different answer from what is already there.

    – Neil Lunn
    Nov 25 '18 at 10:56


















3















My Problem



The ESLint airbnb policy disallows for...of loop iterations, and prefers forEach((element) => { code });. However, inner returns from that loop are swallowed - they are considered returns of the anonymous function rather than the function that embraces the loop.



Code



Original



Works, but breaks eslint-config-airbnb.






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator1() {
const wordlist = ;
for (const word of words) {
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
}
return wordlist;
}

console.log(NestedIterator1());





Alternative 1: Iterating array indices



Works, but the style is outdated and I have to manually assign values by indices.






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;


function NestedIterator2() {
const wordlist = ;
for (let i = 0; i < words.length; i += 1) {
const word = words[i];
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
}
return wordlist;
}


console.log(NestedIterator2());





Alternative 2: Using forEach



Adheres to the style guide, but does not work - the inner returns are considered returns from the anonymous function, rather than the NestedIterator3.






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator3() {
const wordlist = ;
words.forEach((word) => {
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
});
return wordlist;
}

console.log(NestedIterator3());





My Question



How can a function iterate over an array while allowing early returns and avoiding indices and for..of iterations?










share|improve this question


















  • 3





    Well is it really necessary? I defer to the actual reason in the style guide: "Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects.". Whilst I agree that avoiding mutability is grand, saying that for..in or for..of is prone to breaking that is a bit of a stretch. Therefore the rule seems questionable and probably should be overridden

    – Neil Lunn
    Nov 25 '18 at 10:34











  • throwing exception inside of forEach callback with try .. catch would work like break but I believe it'd be more confusing than eslint warning or per-file suppressing the rule

    – skyboyer
    Nov 25 '18 at 10:39






  • 1





    @skyboyer Agree. It's not exactly a "unique" question and has certainly been asked before Short circuit Array.forEach like calling break. I'd rather the OP generally acknowledge the duplicate for themselves. Certainly can't see how there would be a completely different answer from what is already there.

    – Neil Lunn
    Nov 25 '18 at 10:56
















3












3








3








My Problem



The ESLint airbnb policy disallows for...of loop iterations, and prefers forEach((element) => { code });. However, inner returns from that loop are swallowed - they are considered returns of the anonymous function rather than the function that embraces the loop.



Code



Original



Works, but breaks eslint-config-airbnb.






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator1() {
const wordlist = ;
for (const word of words) {
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
}
return wordlist;
}

console.log(NestedIterator1());





Alternative 1: Iterating array indices



Works, but the style is outdated and I have to manually assign values by indices.






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;


function NestedIterator2() {
const wordlist = ;
for (let i = 0; i < words.length; i += 1) {
const word = words[i];
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
}
return wordlist;
}


console.log(NestedIterator2());





Alternative 2: Using forEach



Adheres to the style guide, but does not work - the inner returns are considered returns from the anonymous function, rather than the NestedIterator3.






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator3() {
const wordlist = ;
words.forEach((word) => {
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
});
return wordlist;
}

console.log(NestedIterator3());





My Question



How can a function iterate over an array while allowing early returns and avoiding indices and for..of iterations?










share|improve this question














My Problem



The ESLint airbnb policy disallows for...of loop iterations, and prefers forEach((element) => { code });. However, inner returns from that loop are swallowed - they are considered returns of the anonymous function rather than the function that embraces the loop.



Code



Original



Works, but breaks eslint-config-airbnb.






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator1() {
const wordlist = ;
for (const word of words) {
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
}
return wordlist;
}

console.log(NestedIterator1());





Alternative 1: Iterating array indices



Works, but the style is outdated and I have to manually assign values by indices.






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;


function NestedIterator2() {
const wordlist = ;
for (let i = 0; i < words.length; i += 1) {
const word = words[i];
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
}
return wordlist;
}


console.log(NestedIterator2());





Alternative 2: Using forEach



Adheres to the style guide, but does not work - the inner returns are considered returns from the anonymous function, rather than the NestedIterator3.






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator3() {
const wordlist = ;
words.forEach((word) => {
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
});
return wordlist;
}

console.log(NestedIterator3());





My Question



How can a function iterate over an array while allowing early returns and avoiding indices and for..of iterations?






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator1() {
const wordlist = ;
for (const word of words) {
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
}
return wordlist;
}

console.log(NestedIterator1());





const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator1() {
const wordlist = ;
for (const word of words) {
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
}
return wordlist;
}

console.log(NestedIterator1());





const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;


function NestedIterator2() {
const wordlist = ;
for (let i = 0; i < words.length; i += 1) {
const word = words[i];
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
}
return wordlist;
}


console.log(NestedIterator2());





const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;


function NestedIterator2() {
const wordlist = ;
for (let i = 0; i < words.length; i += 1) {
const word = words[i];
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
}
return wordlist;
}


console.log(NestedIterator2());





const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator3() {
const wordlist = ;
words.forEach((word) => {
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
});
return wordlist;
}

console.log(NestedIterator3());





const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator3() {
const wordlist = ;
words.forEach((word) => {
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
if (wordlist.length >= MAX_WORDS) {
return wordlist;
}
});
return wordlist;
}

console.log(NestedIterator3());






node.js short-circuiting early-return






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 25 '18 at 10:22









Adam MatanAdam Matan

50.7k95266421




50.7k95266421








  • 3





    Well is it really necessary? I defer to the actual reason in the style guide: "Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects.". Whilst I agree that avoiding mutability is grand, saying that for..in or for..of is prone to breaking that is a bit of a stretch. Therefore the rule seems questionable and probably should be overridden

    – Neil Lunn
    Nov 25 '18 at 10:34











  • throwing exception inside of forEach callback with try .. catch would work like break but I believe it'd be more confusing than eslint warning or per-file suppressing the rule

    – skyboyer
    Nov 25 '18 at 10:39






  • 1





    @skyboyer Agree. It's not exactly a "unique" question and has certainly been asked before Short circuit Array.forEach like calling break. I'd rather the OP generally acknowledge the duplicate for themselves. Certainly can't see how there would be a completely different answer from what is already there.

    – Neil Lunn
    Nov 25 '18 at 10:56
















  • 3





    Well is it really necessary? I defer to the actual reason in the style guide: "Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects.". Whilst I agree that avoiding mutability is grand, saying that for..in or for..of is prone to breaking that is a bit of a stretch. Therefore the rule seems questionable and probably should be overridden

    – Neil Lunn
    Nov 25 '18 at 10:34











  • throwing exception inside of forEach callback with try .. catch would work like break but I believe it'd be more confusing than eslint warning or per-file suppressing the rule

    – skyboyer
    Nov 25 '18 at 10:39






  • 1





    @skyboyer Agree. It's not exactly a "unique" question and has certainly been asked before Short circuit Array.forEach like calling break. I'd rather the OP generally acknowledge the duplicate for themselves. Certainly can't see how there would be a completely different answer from what is already there.

    – Neil Lunn
    Nov 25 '18 at 10:56










3




3





Well is it really necessary? I defer to the actual reason in the style guide: "Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects.". Whilst I agree that avoiding mutability is grand, saying that for..in or for..of is prone to breaking that is a bit of a stretch. Therefore the rule seems questionable and probably should be overridden

– Neil Lunn
Nov 25 '18 at 10:34





Well is it really necessary? I defer to the actual reason in the style guide: "Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side effects.". Whilst I agree that avoiding mutability is grand, saying that for..in or for..of is prone to breaking that is a bit of a stretch. Therefore the rule seems questionable and probably should be overridden

– Neil Lunn
Nov 25 '18 at 10:34













throwing exception inside of forEach callback with try .. catch would work like break but I believe it'd be more confusing than eslint warning or per-file suppressing the rule

– skyboyer
Nov 25 '18 at 10:39





throwing exception inside of forEach callback with try .. catch would work like break but I believe it'd be more confusing than eslint warning or per-file suppressing the rule

– skyboyer
Nov 25 '18 at 10:39




1




1





@skyboyer Agree. It's not exactly a "unique" question and has certainly been asked before Short circuit Array.forEach like calling break. I'd rather the OP generally acknowledge the duplicate for themselves. Certainly can't see how there would be a completely different answer from what is already there.

– Neil Lunn
Nov 25 '18 at 10:56







@skyboyer Agree. It's not exactly a "unique" question and has certainly been asked before Short circuit Array.forEach like calling break. I'd rather the OP generally acknowledge the duplicate for themselves. Certainly can't see how there would be a completely different answer from what is already there.

– Neil Lunn
Nov 25 '18 at 10:56














1 Answer
1






active

oldest

votes


















3














One option would be to use reduce, which is very flexible and can be used in many situations where the other iteration methods aren't sufficient - only push to the accumulator if the accumulator's length is smaller than MAX_WORDS and of the word's length is sufficient:






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator3() {
return words.reduce((wordlist, word) => {
if (wordlist.length < MAX_WORDS && word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
return wordlist;
}, );
}

console.log(NestedIterator3());





Still, the above method does iterate over all indicies - it doesn't actually return early, it just doesn't do anything in the later iterations once the end condition has been fulfilled. If you want to actually break out of the iterator, you could use .some instead, although it's even more impure, and the intent of the code is slightly less clear IMO:






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator3() {
const wordlist = ;
words.some((word) => {
if (word.length >= MIN_WORD_SIZE) {
wordlist.push(word);
}
return wordlist.length === MAX_WORDS;
}, );
return wordlist;
}

console.log(NestedIterator3());





For this particular example, you could also use filter followed by slice:






const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

const MIN_WORD_SIZE = 4;
const MAX_WORDS = 3;

function NestedIterator3() {
return words
.filter(word => word.length >= MIN_WORD_SIZE)
.slice(0, MAX_WORDS)
}

console.log(NestedIterator3());





which certainly looks far more elegant, but the .filter necessarily iterates over all items in the array first, and so has the same problem as the reduce (no short-circuiting is going on) - in addition, those two chained methods only represent a subset of the situations in which one might want to short-circuit array iteration.






share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53466565%2fnode-js-combining-foreach-with-early-returns%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    3














    One option would be to use reduce, which is very flexible and can be used in many situations where the other iteration methods aren't sufficient - only push to the accumulator if the accumulator's length is smaller than MAX_WORDS and of the word's length is sufficient:






    const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

    const MIN_WORD_SIZE = 4;
    const MAX_WORDS = 3;

    function NestedIterator3() {
    return words.reduce((wordlist, word) => {
    if (wordlist.length < MAX_WORDS && word.length >= MIN_WORD_SIZE) {
    wordlist.push(word);
    }
    return wordlist;
    }, );
    }

    console.log(NestedIterator3());





    Still, the above method does iterate over all indicies - it doesn't actually return early, it just doesn't do anything in the later iterations once the end condition has been fulfilled. If you want to actually break out of the iterator, you could use .some instead, although it's even more impure, and the intent of the code is slightly less clear IMO:






    const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

    const MIN_WORD_SIZE = 4;
    const MAX_WORDS = 3;

    function NestedIterator3() {
    const wordlist = ;
    words.some((word) => {
    if (word.length >= MIN_WORD_SIZE) {
    wordlist.push(word);
    }
    return wordlist.length === MAX_WORDS;
    }, );
    return wordlist;
    }

    console.log(NestedIterator3());





    For this particular example, you could also use filter followed by slice:






    const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

    const MIN_WORD_SIZE = 4;
    const MAX_WORDS = 3;

    function NestedIterator3() {
    return words
    .filter(word => word.length >= MIN_WORD_SIZE)
    .slice(0, MAX_WORDS)
    }

    console.log(NestedIterator3());





    which certainly looks far more elegant, but the .filter necessarily iterates over all items in the array first, and so has the same problem as the reduce (no short-circuiting is going on) - in addition, those two chained methods only represent a subset of the situations in which one might want to short-circuit array iteration.






    share|improve this answer






























      3














      One option would be to use reduce, which is very flexible and can be used in many situations where the other iteration methods aren't sufficient - only push to the accumulator if the accumulator's length is smaller than MAX_WORDS and of the word's length is sufficient:






      const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

      const MIN_WORD_SIZE = 4;
      const MAX_WORDS = 3;

      function NestedIterator3() {
      return words.reduce((wordlist, word) => {
      if (wordlist.length < MAX_WORDS && word.length >= MIN_WORD_SIZE) {
      wordlist.push(word);
      }
      return wordlist;
      }, );
      }

      console.log(NestedIterator3());





      Still, the above method does iterate over all indicies - it doesn't actually return early, it just doesn't do anything in the later iterations once the end condition has been fulfilled. If you want to actually break out of the iterator, you could use .some instead, although it's even more impure, and the intent of the code is slightly less clear IMO:






      const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

      const MIN_WORD_SIZE = 4;
      const MAX_WORDS = 3;

      function NestedIterator3() {
      const wordlist = ;
      words.some((word) => {
      if (word.length >= MIN_WORD_SIZE) {
      wordlist.push(word);
      }
      return wordlist.length === MAX_WORDS;
      }, );
      return wordlist;
      }

      console.log(NestedIterator3());





      For this particular example, you could also use filter followed by slice:






      const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

      const MIN_WORD_SIZE = 4;
      const MAX_WORDS = 3;

      function NestedIterator3() {
      return words
      .filter(word => word.length >= MIN_WORD_SIZE)
      .slice(0, MAX_WORDS)
      }

      console.log(NestedIterator3());





      which certainly looks far more elegant, but the .filter necessarily iterates over all items in the array first, and so has the same problem as the reduce (no short-circuiting is going on) - in addition, those two chained methods only represent a subset of the situations in which one might want to short-circuit array iteration.






      share|improve this answer




























        3












        3








        3







        One option would be to use reduce, which is very flexible and can be used in many situations where the other iteration methods aren't sufficient - only push to the accumulator if the accumulator's length is smaller than MAX_WORDS and of the word's length is sufficient:






        const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

        const MIN_WORD_SIZE = 4;
        const MAX_WORDS = 3;

        function NestedIterator3() {
        return words.reduce((wordlist, word) => {
        if (wordlist.length < MAX_WORDS && word.length >= MIN_WORD_SIZE) {
        wordlist.push(word);
        }
        return wordlist;
        }, );
        }

        console.log(NestedIterator3());





        Still, the above method does iterate over all indicies - it doesn't actually return early, it just doesn't do anything in the later iterations once the end condition has been fulfilled. If you want to actually break out of the iterator, you could use .some instead, although it's even more impure, and the intent of the code is slightly less clear IMO:






        const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

        const MIN_WORD_SIZE = 4;
        const MAX_WORDS = 3;

        function NestedIterator3() {
        const wordlist = ;
        words.some((word) => {
        if (word.length >= MIN_WORD_SIZE) {
        wordlist.push(word);
        }
        return wordlist.length === MAX_WORDS;
        }, );
        return wordlist;
        }

        console.log(NestedIterator3());





        For this particular example, you could also use filter followed by slice:






        const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

        const MIN_WORD_SIZE = 4;
        const MAX_WORDS = 3;

        function NestedIterator3() {
        return words
        .filter(word => word.length >= MIN_WORD_SIZE)
        .slice(0, MAX_WORDS)
        }

        console.log(NestedIterator3());





        which certainly looks far more elegant, but the .filter necessarily iterates over all items in the array first, and so has the same problem as the reduce (no short-circuiting is going on) - in addition, those two chained methods only represent a subset of the situations in which one might want to short-circuit array iteration.






        share|improve this answer















        One option would be to use reduce, which is very flexible and can be used in many situations where the other iteration methods aren't sufficient - only push to the accumulator if the accumulator's length is smaller than MAX_WORDS and of the word's length is sufficient:






        const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

        const MIN_WORD_SIZE = 4;
        const MAX_WORDS = 3;

        function NestedIterator3() {
        return words.reduce((wordlist, word) => {
        if (wordlist.length < MAX_WORDS && word.length >= MIN_WORD_SIZE) {
        wordlist.push(word);
        }
        return wordlist;
        }, );
        }

        console.log(NestedIterator3());





        Still, the above method does iterate over all indicies - it doesn't actually return early, it just doesn't do anything in the later iterations once the end condition has been fulfilled. If you want to actually break out of the iterator, you could use .some instead, although it's even more impure, and the intent of the code is slightly less clear IMO:






        const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

        const MIN_WORD_SIZE = 4;
        const MAX_WORDS = 3;

        function NestedIterator3() {
        const wordlist = ;
        words.some((word) => {
        if (word.length >= MIN_WORD_SIZE) {
        wordlist.push(word);
        }
        return wordlist.length === MAX_WORDS;
        }, );
        return wordlist;
        }

        console.log(NestedIterator3());





        For this particular example, you could also use filter followed by slice:






        const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

        const MIN_WORD_SIZE = 4;
        const MAX_WORDS = 3;

        function NestedIterator3() {
        return words
        .filter(word => word.length >= MIN_WORD_SIZE)
        .slice(0, MAX_WORDS)
        }

        console.log(NestedIterator3());





        which certainly looks far more elegant, but the .filter necessarily iterates over all items in the array first, and so has the same problem as the reduce (no short-circuiting is going on) - in addition, those two chained methods only represent a subset of the situations in which one might want to short-circuit array iteration.






        const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

        const MIN_WORD_SIZE = 4;
        const MAX_WORDS = 3;

        function NestedIterator3() {
        return words.reduce((wordlist, word) => {
        if (wordlist.length < MAX_WORDS && word.length >= MIN_WORD_SIZE) {
        wordlist.push(word);
        }
        return wordlist;
        }, );
        }

        console.log(NestedIterator3());





        const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

        const MIN_WORD_SIZE = 4;
        const MAX_WORDS = 3;

        function NestedIterator3() {
        return words.reduce((wordlist, word) => {
        if (wordlist.length < MAX_WORDS && word.length >= MIN_WORD_SIZE) {
        wordlist.push(word);
        }
        return wordlist;
        }, );
        }

        console.log(NestedIterator3());





        const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

        const MIN_WORD_SIZE = 4;
        const MAX_WORDS = 3;

        function NestedIterator3() {
        const wordlist = ;
        words.some((word) => {
        if (word.length >= MIN_WORD_SIZE) {
        wordlist.push(word);
        }
        return wordlist.length === MAX_WORDS;
        }, );
        return wordlist;
        }

        console.log(NestedIterator3());





        const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

        const MIN_WORD_SIZE = 4;
        const MAX_WORDS = 3;

        function NestedIterator3() {
        const wordlist = ;
        words.some((word) => {
        if (word.length >= MIN_WORD_SIZE) {
        wordlist.push(word);
        }
        return wordlist.length === MAX_WORDS;
        }, );
        return wordlist;
        }

        console.log(NestedIterator3());





        const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

        const MIN_WORD_SIZE = 4;
        const MAX_WORDS = 3;

        function NestedIterator3() {
        return words
        .filter(word => word.length >= MIN_WORD_SIZE)
        .slice(0, MAX_WORDS)
        }

        console.log(NestedIterator3());





        const words = ['harry', 'potter', 'and', 'the', 'forbidden', 'journey'];

        const MIN_WORD_SIZE = 4;
        const MAX_WORDS = 3;

        function NestedIterator3() {
        return words
        .filter(word => word.length >= MIN_WORD_SIZE)
        .slice(0, MAX_WORDS)
        }

        console.log(NestedIterator3());






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 25 '18 at 11:13

























        answered Nov 25 '18 at 10:34









        CertainPerformanceCertainPerformance

        92.4k165383




        92.4k165383
































            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53466565%2fnode-js-combining-foreach-with-early-returns%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Create new schema in PostgreSQL using DBeaver

            Deepest pit of an array with Javascript: test on Codility

            Costa Masnaga