【问题标题】:Cartesian Product of multiple array多个数组的笛卡尔积
【发布时间】:2011-12-18 05:38:58
【问题描述】:

我认为这基本上是一个简单的问题,但我被卡住了。我的大脑被这个问题阻塞了,所以我希望你能帮助我。 我有 2 到 N 个整数数组,比如

{1,2,3,4,5}
{1,2,3,4,5,6}
{1,3,5}
.....

现在我想要一个包含 int[N] 数组的列表,每个可能性都像

{1,1,1}
{1,1,3}
{1,1,5}
{1,2,1}
....
{1,3,1}
....
{2,1,1}
{2,1,3}
....
{5,6,5}

所以里面有 6*5*3 (90) 个元素。

有没有一个简单的算法来做到这一点?我认为语言无关紧要,但我更喜欢 Java。

【问题讨论】:

  • 您正在搜索“笛卡尔积算法”。用这个关键字试试 google。
  • 这里 stackoverflow.com/questions/1140164/… 是 Scala 中的一个简短的递归解决方案。
  • @userunknown 抱歉,我看不懂... Scala 很奇怪,我从未使用过它... 其他递归解决方案值得赞赏
  • 你可以在这里找到一个使用 numpy 的 python 实现:stackoverflow.com/questions/1208118/…

标签: arrays algorithm list multidimensional-array


【解决方案1】:

据我了解你想要什么,你需要得到所有排列。

使用递归算法,详解here

【讨论】:

  • 我认为 OP 想要 2 到 N 个集合的笛卡尔积,而不是给定集合的排列。
  • 这让我很困惑。我现在需要什么?注意我编辑了问题
  • 我错了。现在我得到了你想要的。使用 AurelioDeRosa 的建议
【解决方案2】:

感谢您的帮助! 我为下一个遇到同样问题的人添加了一个有效的答案,并在 java 中实现。我也这样做是通用的,所以你可以在任何对象上拥有任何笛卡尔产品,而不仅仅是整数:

public class Product {

    @SuppressWarnings("unchecked")
    public static <T> List<T[]> getCartesianProduct(T[]... objects){
        List<T[]> ret = null;
        if (objects != null){               
            //saves length from first dimension. its the size of T[] of the returned list
            int len = objects.length;
            //saves all lengthes from second dimension
            int[] lenghtes = new int[len];
            // arrayIndex
            int array = 0;
            // saves the sum of returned T[]'s
            int lenSum = 1;
            for (T[] t: objects){
                lenSum *= t.length;
                lenghtes[array++] = t.length;
            }
            //initalize the List with the correct lenght to avoid internal array-copies
            ret = new ArrayList<T[]>(lenSum);
            //reusable class for instatiation of T[]
            Class<T> clazz = (Class<T>) objects[0][0].getClass();
            T[] tArray;
            //values stores arrayIndexes to get correct values from objects
            int[] values = new int[len];

            for (int i = 0; i < lenSum; i++){
                tArray = (T[])Array.newInstance(clazz, len);
                for (int j = 0; j < len; j++){
                    tArray[j] = objects[j][values[j]];
                }
                ret.add(tArray);
                //value counting:
                //increment first value
                values[0]++;
                for (int v = 0; v < len; v++){
                    //check if values[v] doesn't exceed array length
                    if (values[v] == lenghtes[v]){
                        //set it to null and increment the next one, if not the last
                        values[v] = 0;
                        if (v+1 < len){
                            values[v+1]++;
                        }
                    }
                }

            }
        } 
        return ret;
    }
}

【讨论】:

  • 谢谢!这种方法对我来说非常有效(我不能使用递归性能)。如果你去掉泛型并将结果设置为数组数组,性能提升很多!
【解决方案3】:

我认为这应该可以正常工作:

concatMap (λa -> concatMap (λb -> concatMap (λc -> (a,b,c)) L3) L2) L1

concatMap(在 C# 中称为 SelectMany)定义为

concatMap f l = concat (map f l)。

map 将一个函数映射到一个列表上

而 concat(有时称为 flatten)获取 List 的 List 并将其转换为平面 List

【讨论】:

    猜你喜欢
    • 2016-07-10
    • 1970-01-01
    • 2022-01-17
    • 2012-05-14
    相关资源
    最近更新 更多