Generate all selections of K items from a set of N items in C#

selections

This example is somewhat similar to Generate all of the permutations of a set of objects in C#. The basic idea is to use a recursive method to assign the next item to the combination. The first call to the method assigns the combination’s first item, the next call assigns the second item, and so forth until the combination is complete.

To assign an item, the method loops through all of the objects looking for those that have not already been assigned. When it finds such an item, the method:

  • Marks the item as used in the current permutation.
  • Recursively calls itself to assign the next item in the current permutation.
  • When the recursive call returns, the method unmarks the item so it is not used and can be used again later.

The recursion continues until the combination contains the right number of items. Then the method reads the items that are selected in the current combination and adds them to the list of results.

The methods used by this program are generic. In this example they use strings because that’s what you can easily enter on the form, but you can use the same methods to permute other objects.

The following code shows how the program generates permutations when you click the Go button.

// Generate the combinations.
private void btnGo_Click(object sender, EventArgs e)
{
    // Get the items and N.
    string[] items = txtItems.Text.Split(' ');
    int n = int.Parse(txtNumPerSelection.Text);

    // Generate the selections.
    List<List<string>> results =
        GenerateSelections<string>(items.ToList(), n);

    // Display the results.
    lstSelections.Items.Clear();
    foreach (List<string> combination in results)
    {
        lstSelections.Items.Add(
            string.Join(" ", combination.ToArray()));
    }

    // Calculate the number of items.
    decimal num_combinations = NChooseK(items.Length, n);
    txtNumSelections.Text = num_combinations.ToString();

    // Check the result.
    Debug.Assert(lstSelections.Items.Count == num_combinations);
}

This code makes a list of the words you entered. It calls GenerateSelections and displays the results.

It also calls the NChooseK method to display the number of combinations. For a description of that method, see Calculate the binomial coefficient “N choose K” efficiently in C#.

The GenerateSelections method really just sets up and then calls the following SelectItems method to do the real work.

// Generate selections of n items.
private List> GenerateSelections(List items, int n)
{
    // Make an array to tell whether
    // an item is in the current selection.
    bool[] in_selection = new bool[items.Count];

    // Make a result list.
    List> results = new List>();

    // Build the combinations recursively.
    SelectItems(items, in_selection, results, n, 0);

    // Return the results.
    return results;
}

This method creates an array to indicate which items are in the current selection. It then calls SelectItems, telling it how many items it needs to add to each selection. The SelectItems method, which is shown in the following code, does all of the work.

// Recursively select n additional items with indexes >= first_item.
// If n == 0, add the current combination to the results.
private void SelectItems<T>(List<T> items, bool[] in_selection,
    List<List<T>> results, int n, int first_item)
{
    if (n == 0)
    {
        // Add the current selection to the results.
        List<T> selection = new List<T>();
        for (int i = 0; i < items.Count; i++)
        {
            // If this item is selected, add it to the selection.
            if (in_selection[i]) selection.Add(items[i]);
        }
        results.Add(selection);
    }
    else
    {
        // Try adding each of the remaining items.
        for (int i = first_item; i < items.Count; i++)
        {
            // Try adding this item.
            in_selection[i] = true;

            // Recursively add the rest of the required items.
            SelectItems(items, in_selection, results, n - 1, i + 1);

            // Remove this item from the selection.
            in_selection[i] = false;
        }
    }
}

The method first checks whether the current selection needs more items. If it does not, it adds the current selection to the results and returns.

If the current selection needs more items, the code loops through all of the items. When it finds an item that is not yet in the selection, the method adds that item to the selection and calls itself recursively to select more items if necessary. When the recursive call returns, the method unmarks the item it added and continues looping through the remaining items.


Download Example   Follow me on Twitter   RSS feed




This entry was posted in algorithms, combinatorics, mathematics and tagged , , , , , , , , , , , , , , , . Bookmark the permalink.

3 Responses to Generate all selections of K items from a set of N items in C#

  1. Frixum says:

    Hi,
    Great work,
    if we have population A B C with position size 2 then total arrangements would be
    3P2 = 6.
    but this program only generates 3 arrangements.
    like A B C for size 2 it creates
    AB
    AC
    BC

    and these terms are missing
    BA
    CA
    CB
    your all permutations example works fine and generates total n! of arrangements.
    Please suggest

    • Frixum says:

      I have resolved this 🙂
      in “Generate all of the permutations of a set of objects in C#” program,
      I have altered this line
      // See if all of the positions are filled.
      if (next_position == items.Count)

      with this line
      // See if all of the positions are filled.
      if (next_position == txtNumPerSelection.Text)

      and it worked. A B C D E for size 3 it generates prefect 120 arrangements.
      Thanks

    • RodStephens says:

      This program generates unordered arrangements so it considers AB and BA to be the same.

      I’m glad you got it working. Another approach would be to take the output of this program and then generate permutations for its results.

Leave a Reply

Your email address will not be published. Required fields are marked *