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

Navigating an Array in Typescript

Angular is linked to node.js, which interacts with mongodb to fetch data successfully. However, I am now faced with the challenge of mapping variables in my typescript component to the backend node.js. When viewing the data structure in the browser consol ...

Creating Algorithms for Generic Interfaces in TypeScript to Make them Compatible with Derived Generic Classes

Consider the (simplified) code: interface GenericInterface<T> { value: T } function genericIdentity<T>(instance : GenericInterface<T>) : GenericInterface<T> { return instance; } class GenericImplementingClass<T> implemen ...

The Material UI theme of a React component is not locally scoped within the Shadow DOM

Introduction I have embarked on a project to develop a Chrome Extension that utilizes a React component through the Content script. The React component I am working with is a toolbar equipped with various sub-tools for users to interact with while browsin ...

Experiencing issues with a blank or non-functional DataGrid in Material UI components

My DataGrid table is showing blank. I experienced the same problem in a previous project and recreated it in a new one with updated versions of django and mui libraries. Here is an example of my data displayed with DataGrid not working I posted a bug rep ...

How can I remove a specific JSON object from localStorage based on the data associated with the element that is currently being clicked on?

Unique Scenario A user interacts with an element, triggering a change in the background image and storing data related to that element in localStorage: this process functions correctly. Next, the toggle variable is set to 0, the background image change ...

delay of Paypal API disbursement for transactions with a range of money values

After browsing through various resources such as this link, that link, and another one on the PayPal developer website, I attempted to implement a payment processing system that allows users to approve a preset amount of money. Similar to services like Ube ...

Using custom properties from the Material-UI theme object with custom props in Emotion styled components: a step-by-step guide

I have implemented a custom object called fTokens into the MUI theme using Module augmentation in TypeScript This is how my theme.d.ts file is structured declare module "@mui/material/styles" { interface FPalette { ... } interface FTokens ...

mysql nodejs function is returning a null value

Kindly review the contents of the dbfn.js file /*This is the database function file*/ var db = require('./connection'); function checkConnection(){ if(db){ console.log('We are connected to the Database server'.bgGreen); ...

Controller property not being updated by directive

I have developed a custom directive to identify when the enter key is pressed within a text box. Here's the implementation of the directive: import { BookmarkService } from "../services/bookmarkService"; import { qlik, QlikBookmarkInfo } from "../qli ...

Can you place more than one Twitter Bootstrap carousel on a single webpage?

Latest Version of Twitter Bootstrap: 2.0.3 Sample HTML Code: <!DOCTYPE html> <html dir="ltr" lang="en-US" xmlns:og="http://opengraphprotocol.org/schema/"> <head> <link rel="stylesheet" type="text/css" media="all" href="reddlec/style. ...

Tips for transforming a string into an object using AngularJS

Here is a string I'm working with: $scope.text = '"{\"firstName\":\"John\",\"age\":454 }"'; I am trying to convert it into a JavaScript object: $scope.tmp = {"firstName":"John","age":454 }; Please note: J ...

Obtaining Position Coordinates of an Element Linked to an Object in AngularJS $scope

Imagine a website with a left column containing filters like checkboxes and text fields. The main column displays items that are filtered based on the values provided in the left column. When a user changes a value in the filter column, a small floating el ...

Struggling to find the element using Selenium

Hey there, I'm struggling with identifying the input id button in my HTML code while using Selenium through Java. The error message says it's unable to locate the element. Can anyone provide some guidance? I've already tried using xpath and ...

Tips for using parsley on a dynamically loaded webpage

I'm encountering an issue with applying validation for a datepicker in AJAX loaded content. The validation doesn't seem to work for the loaded content. Can someone please assist me with this? /Script/ function applyValidationForDatepicker(feest ...

What is the best method to retrieve a nested JSON property that is deeply embedded within

I am facing an issue with storing a HEX color code obtained from an API in a Vue.js app. The object app stores the color code, for example: const app = {"theme":"{\"color\":\"#186DFFF0\"}"}. However, when I try to access the color prope ...

Dynamic Type in Typescript Record

Looking for a way to attach types to record names in a class that returns a Record. The current code snippet is as follows: interface DataInterface { bar: number; foo: string; fooBar: boolean; } export class MyClass { public bar: number; p ...

Dealing with illegal characters, such as the notorious £ symbol, in JSON data within a JQuery

I'm encountering an issue with a textarea and the handling of special symbols. Specifically, when I use $('#mytextarea').val() to retrieve text that contains '£', I end up seeing the black diamond with a question mark inside it. T ...

Pagination Component for React Material-UI Table

I am interested in learning about Table Pagination in React UI Material. Currently, my goal is to retrieve and display data from an API in a Material UI Table. While I have successfully implemented some data from the API into the Material UI Table, I am ...

Internet Explorer 10 not triggering the 'input' event when selecting an option from the datalist

Within this particular scenario, there is an input field paired with a corresponding datalist element. My aim is to develop JavaScript code that actively listens for when a user chooses an item from the list. Most resources suggest utilizing the "input" ev ...

JS Equal Heights is a JavaScript plugin designed to ensure

Good evening, A while back, I implemented a JavaScript code snippet to create equal height columns on my website. The initial script looked like this: <script type="text/javascript"> var maxHeight = 0; $(".level").each(function(){ maxHe ...