使用 Ada 的列表的笛卡尔积

Cartesian Product of Lists Using Ada

我目前正致力于在 Ada 中对此 (https://rosettacode.org/wiki/Cartesian_product_of_two_or_more_lists) 进行编程,我正在尝试在不同集合之间进行笛卡尔积。我需要帮助弄清楚,主要问题是我如何能够声明空对并计算如果它是空的,那么结果应该是空的。谢谢!

我尝试使用的号码:

{1, 2} × {3, 4}
{3, 4} × {1, 2}
{1, 2} × {}
{} × {1, 2}

我的代码:

with Ada.Text_IO; use Ada.Text_IO; -- Basically importing the functions that will be used to print out the results.

procedure Hello is -- Procedure is where variables & functions are declared!
    type T_Pair is array(1..2) of Integer; -- Declare a type of array that contains a set of 2 numbers (Used for final result!).
    type T_Result is array(1..4) of T_Pair; -- Declare a type of array that contains a set of T_Pair(s), used to hold the result.

    Demo1 : T_Result;
    Demo1A : T_Pair := (1, 2);
    Demo1B : T_Pair := (3, 4);


    function Fun_CartProd(p1: T_Pair; p2: T_Pair) return T_Result is
        results: T_Result;
        i: integer := 1;
    begin
        for j in 1..2 loop
            for h in 1..2 loop
                results(i) := (p1(j), p2(h));
                i := i + 1;
            end loop;
        end loop;
        return results;
    end Fun_CartProd;
begin -- This is where the statements go
    Demo1 := Fun_CartProd(Demo1A, Demo1B);
    for K in 1 .. Demo1'length loop
        Put(" [");
        for B in 1 .. Demo1(K)'length loop
            Put(Integer'Image(Demo1(K)(B)));
            if Demo1(K)'length /= B then
                Put(",");
            end if;
        end loop;
        Put("]");
        if Demo1'length /= K then
            Put(",");
        end if;
    end loop;
    Put_Line(""); -- Create a new line.
end Hello;

由于每组整数可以是任意长度,包括空的,我将从一个可以处理所有这些情况的类型开始:

type Integer_Set is array(Positive range <>) of Integer; -- Input type
type Integer_Tuple is array(Positive range <>_ of Integer; -- Output type

你可以这样表示空集和元组:

Empty_Set : constant Integer_Set(1..0) := (others => <>);
Empty_Tuple : constant Integer_Tuple(1..0) := (others => <>);

另一个问题不仅仅是每个集合中有多少个元素,而是您将找到多少个集合的乘积。为此,我会推荐某种容器。数组在这里不起作用,因为每个单独的集合都可以有不同的大小(包括空的),但 Ada 有多种 "indefinite" 容器可以处理这个问题。下面是一个使用向量的例子:

package Set_Vectors is new Ada.Containers.Indefinite_Vectors
   (Index_Type   => Positive,
    Element_Type => Integer_Set);
package Tuple_Vectors is new Ada.Containers.Indefinite_Vectors
   (Index_Type   => Positive,
    Element_Type => Integer_Tuple);

然后您可以将空结果表示为:

Empty_Tuple_Vector : constant Tuple_Vectors.Vector := Tupler_Vectors.Empty_Vector;

现在您可以创建一个接受集合向量和return笛卡尔积的函数,后者也将是集合向量:

function Cartesian_Product(Inputs : Set_Vectors.Vector) return Tuple_Vectors.Vector;

如果其中一个输入集为空,您 return 一个 Empty_Tuple_Vector。您可以通过检查输入集的长度属性结果来检查其中一个输入集是否为空。如果它们为空,则为 0。此外,如果输入向量完全为空,您可以决定 return Empty_Tuple_Vector 或引发异常。例如:

if Inputs'Length = 0 then
   return Empty_Tuple_Vector;  -- or raise an exception, etc.
end if;

for Set of Inputs loop
   if Set'Length = 0 then
      return Empty_Tuple_Vector;
   end if;
   -- Maybe do other stuff here if you need
end loop;

请注意,您提供的逻辑仅假定输入对。我没有足够的经验来转换您的逻辑以说明可变输入,但如果您需要,也许有人可以对此发表评论。

另请注意,正如 Flyx 评论的那样,这不会在语义上检查一个集合是否是输入的集合(即没有重复值)。