Get every possible combination of a specified length without any repeated elements

Here is the input I am working with:

interface Option{
  name:string
  travelMode:string
}

const options:Option[] = [
  {
    name:"john",
    travelMode:"bus"
  },
  {
    name:"john",
    travelMode:"car"
  },
  {
    name:"kevin",
    travelMode:"bus"
  },
  {
    name:"kevin",
    travelMode:"car"
  },
]

I am trying to find all possible combinations of length 2 within this collection. To achieve this, I have implemented the following function :

const getCombinations=(options:Option[],startIndex:number,combination:Option[],combinationSize:number)=>{
  if (combination.filter(e => e!==undefined).length === combinationSize)
  {
    console.log(combination)
  }
  else if (startIndex<options.length){
    combination[startIndex]=undefined
    getCombinations(options,startIndex+1,combination,combinationSize)


    combination[startIndex]=options[startIndex]
    getCombinations(options,startIndex+1,combination,combinationSize)
  }
}

getCombinations(options,0,[],2)

The output looks promising, but I have a concern and an issue to resolve:

My concern: Why do all the printed combinations have a length of 4? According to my logic, the recursion should stop once we have 2 defined elements. I am puzzled as to why the last combination in the output has 4 elements (the first 2 are defined and the remaining 2 are undefined) => It seems like the program continues to iterate even after having 2 elements in its combination, which is not what I intended.

Issue to resolve: I want to exclude combinations where the names are the same. I only want combinations with 2 distinct names (i.e., john and kevin, but not john and john or kevin and kevin). Initially, I thought about calculating all combinations and then removing the duplicates at the end, but that doesn't seem efficient, especially when dealing with larger datasets. So, I attempted an alternative solution (stop the program if an individual has already been visited):

const getCombinations=(options:Option[],startIndex:number,combination:Option[],combinationSize:number)=>{
  if (combination.filter(e => e!==undefined).length === combinationSize)
  {
    console.log(combination)
  }
  else if (startIndex<options.length){
    combination[startIndex]=undefined
    getCombinations(options,startIndex+1,combination,combinationSize)

    let individualAlreadyVisited = false
    if (startIndex>0)
    {
      for (let i =0;i<startIndex;i++)
      {
        if (combination[i] && combination[i].name===options[startIndex].name)
        {
          individualAlreadyVisited=true
          break
        }
      }
    }

    if (!individualAlreadyVisited)
    {
      combination[startIndex]=options[startIndex]
      getCombinations(options,startIndex+1,combination,combinationSize)
    }
  }
}

getCombinations(options,0,[],2)

Unfortunately, this approach is not yielding the expected results. The output still contains combinations with repeated names and some combinations seem to be missing. For example, the combination { name: 'john', travelMode: 'bus' }, { name: 'kevin', travelMode: 'car' } is not being displayed.

If anyone could provide assistance on this matter, I would greatly appreciate it. I have invested several hours into understanding and achieving the desired outcome without success so far.

Answer №1

The potential source of confusion lies in the act of altering the array during the recursive procedures. This not only complicates the code readability but also makes debugging a challenging task.

An effective approach would involve utilizing a generator function to iterate through the array, selecting the element at the current index, and generating combinations using n - 1 subsequent elements:

 function* generateCombinations<T>(array: T[], n: number, start = 0, previous: T[] = []) {
   if(n <= 0) {
     yield previous;
     return;
   }

   for(let index = start; index <= array.length - n; index++) {
     yield* generateCombinations(array, n - 1, index + 1, [...previous, array[index]]);
   }
 }

 const finalResult = [...generateCombinations([1, 2, 3, 4], 2)];

To address any additional requirements, you can exclude elements that have already been included by implementing the following check:

   if(previous.some(element => compare(element, array[index]))) continue;

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 most effective way to compare a property with the values stored in an array of objects?

d : {"children":[{"name":"China","children":[{"name":"China","value":400,"percentage":"33.33"}],"index":0},{"name":"England","children":[{"name":"England","value":300,"percentage":"33.33"}],"index":1},{"name":"Malaysia","children":[{"name":"Malaysia","val ...

Error encountered in NEXT JS: Unable to parse URL from /api/projects or Error message: Failed to connect to 127.0.0.1:3000

Currently utilizing: export const getStaticProps = async () => { export const getStaticPaths = async () => { and accessing my API (pages/api/projects/) created with Next.js on my local host const res = await fetch("http://localhost:3000/api/ ...

Unveiling an HTML file using the express.static middleware on Replit

When using Replit to render an HTML file with res.sendFile within an app.get function, everything works smoothly. I can include logos, styles, and JavaScript logic files by utilizing the express.static middleware. However, if I attempt to also make the HTM ...

The intended functionality of clicking on an image is exclusively reserved for its immediate parent element

I have a feature on my website that displays an image gallery. When a user clicks on an image, it opens up the image in full screen similar to Facebook's theatre mode. I have written code so that when the user clicks anywhere in the container of the i ...

Navigating with VueRouter in your Chrome Extension is a breeze

I have been working on a Chrome extension using Vue 3 + VueRouter. One issue I encountered was trying to change the router-view content to display a different component, essentially showing users a different UI. Despite my efforts and various methods use ...

Component fails to trigger @click handler

.vue component <template> <div class="modal"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> Loading Files </div> < ...

Struggling to retrieve the value from ng-model?

Currently, I am utilizing this account due to being logged into Facebook on my other account and not having access to my phone for the verification code process. On another note, I am struggling to retrieve the value from an ng-model despite numerous atte ...

The rsuite table does not properly reflect changes in state data

This is the render method that I am working on render() { return ( <Contentbox> <ol> {this.state.data.map((obj) => ( <li key={obj._id}>{obj.name}</li> ) ...

AngularJS encountering unresponsive resources

When setting up my Angular App, I include various resources like this: angular.module('myApp', ['infinite-scroll', 'chieffancypants.loadingBar', 'ngResource']) Next, in the html file: <script type="text/javascr ...

What could be causing my Apollo useLazyQuery to be triggered unexpectedly within a React hook?

import { useLazyQuery } from '@apollo/client'; import { useEffect, useState } from 'react'; import { ContestSessionResponseInfoObject, GetSessionDocument, HasAccessToRoundDocument, } from '@/graphql/generated/shikho-private- ...

Retrieving text from Node.js with the help of regular expressions

I need to extract testcase ids from a list of testcases with titles. Each title includes an id and a description. I want to extract only the id. Here are some examples: TC-ABC-98.1.010_1-Verify the layout credit page TC-RegPMP-1.1.001_2-Verify the [MangerD ...

Utilizing Jest to Mock a jQuery Method within a Promise

I have created a function that utilizes a jQuery function named dataFunc, which is expected to return an object. Instead of testing the dataFunc function itself, I want to focus on testing the promise it produces. To achieve this, I need to mock the respo ...

Using the select method in JavaScript arrays

Are the functionalities of JavaScript and Ruby similar? array.select {|x| x > 3} Could it be done like this instead: array.select(function(x) { if (x > 3) return true}) ...

Encountering an error while trying to load a CSS file in a React project using webpack due

I'm currently working on a React project that utilizes styled components, and I've been attempting to integrate a CSS file as part of the react-image-gallery package. Following the instructions provided, I included the css-loader and style-loade ...

Tips on changing the outline color by clicking

I'm working on a simple code where I need to change the outline color when a user clicks on a text field. <input type="text" id="box1" /> <input type="password" id="box2" /> <input type="email" id="box3" /> <input type="submit" ...

Is there a way to change the color of just the most recently clicked anchor element <a>?

I have a sidebar with anchor elements (Link 1,2,3 in my HTML). I want the text color of these anchors to change when clicked. Additionally, I need only one anchor element to be colored at a time, meaning the previous one should return to its normal color. ...

Create a parent dropdown class that contains two separate bootstrap dropdowns nested within it

I am encountering an issue with my dropdown menus. I have 2 dropdown menu items under the same parent dropdown class. However, when I click on dropdown action 1, it displays the body of dropdown menu 2 items instead. <!DOCTYPE html> <html> < ...

IE11 blocking .click() function with access denied message

When attempting to trigger an auto click on the URL by invoking a .click() on an anchor tag, everything works as expected in most browsers except for Internet Explorer v11. Any assistance would be greatly appreciated. var strContent = "a,b,c\n1,2,3& ...

The Node.js execSync functionality is not functioning as expected, as the changes made to the system are not taking effect

I'm looking to prevent chrome.exe from accessing the internet through the Windows firewall. The specific command I need to use is netsh advfirewall firewall add rule name="Block Chrome" dir=out action=block program="C:\Program Files (x86)\G ...

AngularJS does not support the 'Access-Control-Allow-Origin' header

I'm struggling to find a solution for the cross-domain issue in my code: $apiUrl = 'https://gtmetrix.com/api/0.1/test'; $apiUser = '<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c2a8ada755e4b3afb5bcb9acabb ...