获得多个阵列的独特变体

时间:2017-05-18 08:01:09

标签: php arrays performance multidimensional-array variations

我有一个阵列,其中有不同的项目,例如衬衫,鞋子,领带,夹克等。这些项目中的每一个都可以有多个由其ID表示的设计。

$variations = array(
    'shirts' => array('2'),
    'shoes' => array('7', '3'),
    'jackets' => array('1', '5')
);

现在我们正在寻找一种有效的方法来创建所有这些的不同变体。

## Required result ##
$result = array(
   array('2','7','1'),
   array('2', '7', '5'),
   array('2','3','1'),
   array('2','3','5')
);

任何帮助将不胜感激:)

编辑:我们目前的职能

function cartesian($input) {
    $result = array();

    while (list($key, $values) = each($input)) {
        // If a sub-array is empty, it doesn't affect the cartesian product
        if (empty($values)) {
            continue;
        }

        // Seeding the product array with the values from the first sub-array
        if (empty($result)) {
            foreach($values as $value) {
                $result[] = array($key => $value);
            }
        }
        else {
            // Second and subsequent input sub-arrays work like this:
            //   1. In each existing array inside $product, add an item with
            //      key == $key and value == first item in input sub-array
            //   2. Then, for each remaining item in current input sub-array,
            //      add a copy of each existing array inside $product with
            //      key == $key and value == first item of input sub-array

            // Store all items to be added to $product here; adding them
            // inside the foreach will result in an infinite loop
            $append = array();

            foreach($result as &$product) {
                // Do step 1 above. array_shift is not the most efficient, but
                // it allows us to iterate over the rest of the items with a
                // simple foreach, making the code short and easy to read.
                $product[$key] = array_shift($values);

                // $product is by reference (that's why the key we added above
                // will appear in the end result), so make a copy of it here
                $copy = $product;

                // Do step 2 above.
                foreach($values as $item) {
                    $copy[$key] = $item;
                    $append[] = $copy;
                }

                // Undo the side effecst of array_shift
                array_unshift($values, $product[$key]);
            }

            // Out of the foreach, we can add to $results now
            $result = array_merge($result, $append);
        }
    }

    return $result;
}

2 个答案:

答案 0 :(得分:0)

虽然我同意你的问题下面的评论,但我实现了基于生成器的解决方案,因此无论如何我都可以分享它:

$variations = array(
    'shirts' => array('2'),
    'shoes' => array('7', '3'),
    'jackets' => array('1', '5')
);

var_dump(iterator_to_array(cartesian($variations), false));

function cartesian($lists, $product = []) 
{
        if (empty($product)) {
                // first run, reverse array for array_pop and remove empty lists
                $lists = array_reverse(array_filter($lists, 'count'));
        }
        $curr = array_pop($lists);
        foreach ($curr as $c) {
                if (empty($lists)) {
                        yield array_merge($product, [$c]);
                } else {
                        yield from cartesian($lists, array_merge($product, [$c]));
                }
        }
}

答案 1 :(得分:0)

我就这样做了

$parameters = array(
    'shirts' => array('2'),
    'shoes' => array('7', '3'),
    'jackets' => array('1', '5')
);    
$arPhrases = $parameters[0];

for ($i = 1; $i < count($parameters); $i++) {
    $notFullCount = count($arPhrases);
    foreach ($arPhrases as $phrase) {
        foreach ($parameters[$i] as $newPart) {
            $arPhrases[] = $phrase." ".$newPart;
        }
    }
    $arPhrases = array_slice($arPhrases, $notFullCount);
}