Turning a permutations function into a lazy generator: A step-by-step guide

I am on a mission to generate permutations of an array, one permutation at a time, using a generator.

Here is the existing code (which successfully produces an array of permutations), followed by my attempt to modify it:

function permutations(iList, maxLength) {
        const cur = Array(maxLength)
        const results = []

        function rec(list, depth = 0) {
            if (depth === maxLength) {
                return results.push(cur.slice(0))
            }
            for (let i = 0; i < list.length; ++i) {
                cur[depth] = list.splice(i, 1)[0]
                rec(list, depth + 1)
                list.splice(i, 0, cur[depth])
            }
        }
        rec(iList)
        return results
    }

My updated code, which unfortunately does not produce any output:

function* permutations2(iList, maxLength) {
    const cur = Array(maxLength)

    function* rec(list, depth = 0) {
        if (depth === maxLength) {
            yield cur.slice(0)
        }
        for (let i = 0; i < list.length; ++i) {
            cur[depth] = list.splice(i, 1)[0]
            rec(list, depth + 1)
            list.splice(i, 0, cur[depth])
        }
    }
    yield rec(iList)
}

For instance, with

print(permutations2([1, 2, 3], 2))
, I aim to achieve:

[1, 2]
[1, 3]
[2, 1]
[2, 3]
[3, 1]
[3, 2]

However, with the original code, I receive an array of permutations within arrays:

[[1, 2],
[1, 3],
[2, 1],
[2, 3],
[3, 1],
[3, 2]]

I would appreciate insights into why my code is failing to work and how I can rectify it. Thank you!

Answer №1

A more efficient approach is to utilize a lazy generator.

Rather than immediately returning results, the yield* keyword is used to gradually yield all forthcoming results from the recursive function rec.

In this case, rec functions as a generator as well.

Instead of using return to add to the results array, each result is yielded using yield to optimize performance.

One important modification to make is incorporating an else statement. This ensures that subsequent code does not execute after a yield since it merely pauses execution temporarily.

Within the else block, similar to before, every call to rec should also yield its results.

function* permutations(iList, maxLength) {
    const cur = Array(maxLength)

    function* rec(list, depth = 0) {
        if (depth === maxLength) {
            yield cur.slice(0);
        } else {
            for (let i = 0; i < list.length; ++i) {
                cur[depth] = list.splice(i, 1)[0];

                yield* rec(list, depth + 1);

                list.splice(i, 0, cur[depth])
            }
        }
    }

    yield* rec(iList);
}

console.log([...permutations([1, 2, 3], 2)]);

Although the output remains consistent, the implementation now follows a lazier approach.

Answer №2

If you want to make a change, all you need is to use a generator function and replace return with yield*.

function* permutations(iList, maxLength) {
    const cur = Array(maxLength)
    const results = []

    function rec(list, depth = 0) {
        if (depth === maxLength) {
            return results.push(cur.slice(0))
        }
        for (let i = 0; i < list.length; ++i) {
            cur[depth] = list.splice(i, 1)[0]
            rec(list, depth + 1)
            list.splice(i, 0, cur[depth])
        }
    }
    rec(iList);
    yield* results;
}

console.log([...permutations([1, 2, 3], 2)]);

Keep in mind that this generator is not lazy - it computes all values before yielding them.

yield* is a shortcut for yielding all elements of an iterable or another generator.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to return JSON data as key-value pairs when using the Ajax function $.getJSON()?

Here is the ajax code I'm using to fetch JSON data from a Jobs.json file. $(document).ready(function(){ $('#btn2').click( callJobs ); }); function callJobs() { alert("getting results..."); $.getJSON('Jobs.j ...

Issues with location forecasts and .getPlace() when utilizing the Google Maps loader for Place Autocomplete in Vue are causing functionality problems

After setting up a Vue 2 app using the vue cli, I noticed that when typing an address, no suggestions were populating from the dropdown. Checking the network tab, I observed the AutocompletionService.GetPredictions call triggering without any errors upon p ...

What is the best way to create a flexible Ul-LI menu?

Is it possible to create a flexible menu where clicking on an item does not cover other items in the menu? #demo { margin: 30px 0 50px 0; font-family: sans-serif; } #demo .wrapper { display: inline-block; width: 180px; height: 20px; position ...

jQuery - simply tap or click on most areas to conceal a div and more

$(".clickPlan").click(function(){ $(".panel1").animate({left:'0px'}); }); $(".sendBtn").click(function(){ $(".panel1").animate({left:'300px'}); }); $(document).click(function() { $('.panelBox').fadeOut('fast&ap ...

Executing a task on a deconstructed item within a JavaScript object

function transformTitle (string) { return string.charAt(0).toUpperCase() + string.slice(1) } Looking to capitalize the title directly after destructuring in a single line. const { question } = this.props const { title, Question_uuid: questionUUID } ...

Guide on implementing a redirect to a different page following form submission with the inclusion of a loading screen

<form action='page.html' method='post'> <input type="text" name="name" placeholder="Enter your name here"> <input type="submit" value="submit"> </form> The cod ...

What steps should I take to modify the date format to "dd / mm / yy"?

When using 'toISOString ()' in JavaScript, it appears as shown in photo 2. How can I modify this format? Note: I am working with AngularJs. Image 1 is located in list.component.ts Additional documents: Image 1 Image 2 Image 1: formatDate(e) ...

Merging values within JavaScript objects

Hey everyone, I'm working on a form with various inputs and dropdowns. Depending on the user selections, the final output should be structured like this: var optionVariants = [ { attribute: { id: 1, name: 'Color&ap ...

Encountering an issue with Typescript Interfaces: property not found

This is my custom interface creation export interface UserInfo { success?: boolean, user?: User, employer?: Employer, hr?: Hr } After building this, the next task involves: let data = await loginUser(loginData); console.log(data.success); ...

Issues encountered while establishing a connection to an API in React Native

When attempting to log in a user by connecting to my API, I encountered some issues. It seems that every time my laptop has a different IP address, I need to make changes in the file where the fetch or XMLHttpRequest is located in order for the login proce ...

Is it possible to maintain the life of Jquery through client side interactions?

I have had success using various jQuery keepalive session plugins in the past without any issues. A new request has come up that presents a unique challenge. There are some large forms (created before my time here) on our website where users spend a sign ...

What should I do when encountering the error message "useHref() may only be used within a <Router> component" even though the component is already nested within a <Router>?

I'm currently in the process of writing Jest tests for my React application. When running the tests for the <Container />, I encounter the following error message: "useHref() may only be used within the context of a component." However, the & ...

What steps should I take to fix the TypeScript Compiler issue "Global member 'NodeJS' has no exported namespace 'Global'?"

QUERY: What steps should I take to fix the Typescript Compiler (tsc) error stating "Namespace 'NodeJS' has no exported member 'Global'"? Upon executing tsc, this particular error unexpectedly appeared in a project that is considered "l ...

Interactive Gantt chart tool designed for ReactJs with editable features

Can anyone recommend a dynamic Gantt chart component that is compatible with ReactJS? I specifically need it to display a resource Gantt chart where users can easily manipulate tasks along the time axis and switch between different resources. It would be ...

"Exploring the functionality of HTML buttons on iOS Safari with Angular click

Currently, I am developing a web app that includes a feature where users can hold down a button to adjust a value. The backend of the app is supported by Meteor.js with Angular serving as the front end. The functionality works perfectly, except for Mobile ...

Retrieve Text from a Different <div> Based on Class Using JQuery

Struggling with JQuery, I am trying to access text from another div using only classes. While not fully familiar with JQuery, I manage to make it work most of the time. I attempted something like this: $(function() { $(".quote_button").click( functio ...

What is the best way to implement the Vue router in a separate file?

The vue-router is currently working well, but we are interested in pushing a route from another file. Here is an example of the code: // src/router/index.ts import { route } from 'quasar/wrappers' import VueRouter from 'vue-router' impo ...

While working with AJAX, the variable value remains static and is not refreshed

My jQuery code successfully calls a REST Service and handles the response in the AJAX Success event. However, I'm facing an issue where the variable "SelectedVal" (document.getElementById('Text1').value) is not getting updated with each cli ...

Toggle the visibility of a div based on whether or not certain fields have been filled

Having a form with a repeater field... <table class="dokan-table"> <tfoot> <tr> <th colspan="3"> <?php $file = [ 'file' => ...

"Repetitive cycling, showcasing, and organizing elements in

I have two arrays displayed below and I am trying to calculate the sum, average, and create a summary showing the course along with the grade. grades = new Array(); courses = new Array("Mathematics", "Statistics", "Algorithm"); However, my summary is not ...