[C# Helper]
Index Books FAQ Contact About Rod
[Beginning Database Design Solutions, Second Edition]

[Beginning Software Engineering, Second Edition]

[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

[C# 24-Hour Trainer]

[C# 5.0 Programmer's Reference]

[MCSD Certification Toolkit (Exam 70-483): Programming in C#]

Title: Generate all of the 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 the example to experiment with it and to see additional details.

© 2009-2023 Rocky Mountain Computer Consulting, Inc. All rights reserved.