Task: Combinations with repetitions



C#: using System;
using System.Collections.Generic;
using System.Linq;

public static class MultiCombinations
{
    private static void Main()
    {
        var set = new List<string> { "iced", "jam", "plain" };
        var combinations = GenerateCombinations(set, 2);

        foreach (var combination in combinations)
        {
            string combinationStr = string.Join(" ", combination);
            Console.WriteLine(combinationStr);
        }

        var donuts = Enumerable.Range(1, 10).ToList();

        int donutsCombinationsNumber = GenerateCombinations(donuts, 3).Count;

        Console.WriteLine("{0} ways to order 3 donuts given 10 types", donutsCombinationsNumber);
    }
    
    private static List<List<T>> GenerateCombinations<T>(List<T> combinationList, int k)
    {
        var combinations = new List<List<T>>();

        if (k == 0)
        {
            var emptyCombination = new List<T>();
            combinations.Add(emptyCombination);

            return combinations;
        }

        if (combinationList.Count == 0)
        {
            return combinations;
        }

        T head = combinationList[0];
        var copiedCombinationList = new List<T>(combinationList);
        
        List<List<T>> subcombinations = GenerateCombinations(copiedCombinationList, k - 1);

        foreach (var subcombination in subcombinations)
        {
            subcombination.Insert(0, head);
            combinations.Add(subcombination);
        }

        combinationList.RemoveAt(0);
        combinations.AddRange(GenerateCombinations(combinationList, k));

        return combinations;
    }
}









Ada: with Ada.Text_IO;
procedure Combinations is

   generic
      type Set is (<>);
   function Combinations
     (Count  : Positive;
      Output : Boolean := False)
      return   Natural;

   function Combinations
     (Count  : Positive;
      Output : Boolean := False)
      return   Natural
   is
      package Set_IO is new Ada.Text_IO.Enumeration_IO (Set);
      type Set_Array is array (Positive range <>) of Set;
      Empty_Array : Set_Array (1 .. 0);
      function Recurse_Combinations
        (Number : Positive;
         First  : Set;
         Prefix : Set_Array)
         return   Natural
      is
         Combination_Count : Natural := 0;
      begin
         for Next in First .. Set'Last loop
            if Number = 1 then
               Combination_Count := Combination_Count + 1;
               if Output then
                  for Element in Prefix'Range loop
                     Set_IO.Put (Prefix (Element));
                     Ada.Text_IO.Put ('+');
                  end loop;
                  Set_IO.Put (Next);
                  Ada.Text_IO.New_Line;
               end if;
            else
               Combination_Count := Combination_Count +
                                    Recurse_Combinations
                                       (Number - 1,
                                        Next,
                                        Prefix & (1 => Next));
            end if;
         end loop;
         return Combination_Count;
      end Recurse_Combinations;
   begin
      return Recurse_Combinations (Count, Set'First, Empty_Array);
   end Combinations;

   type Donuts is (Iced, Jam, Plain);
   function Donut_Combinations is new Combinations (Donuts);

   subtype Ten is Positive range 1 .. 10;
   function Ten_Combinations is new Combinations (Ten);

   Donut_Count : constant Natural :=
      Donut_Combinations (Count => 2, Output => True);
   Ten_Count   : constant Natural := Ten_Combinations (Count => 3);
begin
   Ada.Text_IO.Put_Line ("Total Donuts:" & Natural'Image (Donut_Count));
   Ada.Text_IO.Put_Line ("Total Tens:" & Natural'Image (Ten_Count));
end Combinations;