Как получить все комбинации набора данных [duplicate]

Это оптимизация производительности. В результате этой функциональности, какой из этих двух вызовов функций вы считаете более быстрым?

def print_tuple(some_tuple=(1,2,3)):
    print some_tuple

print_tuple()        #1
print_tuple((1,2,3)) #2

Я дам вам подсказку. Вот разборка (см. http://docs.python.org/library/dis.html ):

# 1

0 LOAD_GLOBAL              0 (print_tuple)
3 CALL_FUNCTION            0
6 POP_TOP
7 LOAD_CONST               0 (None)
10 RETURN_VALUE

# 2

 0 LOAD_GLOBAL              0 (print_tuple)
 3 LOAD_CONST               4 ((1, 2, 3))
 6 CALL_FUNCTION            1
 9 POP_TOP
10 LOAD_CONST               0 (None)
13 RETURN_VALUE

Я сомневаюсь, что опытное поведение имеет практическое применение (кто действительно использовал статические переменные в C без размножающихся ошибок?)

blockquote>

] Как вы можете видеть, - преимущество производительности при использовании неизменяемых аргументов по умолчанию. Это может иметь значение, если это часто называемая функция или аргумент по умолчанию занимает много времени, чтобы построить. Кроме того, имейте в виду, что Python не C. В C у вас есть константы, которые в значительной степени свободны. В Python у вас нет этого преимущества.

30
задан Yohan 19 December 2011 в 22:25
поделиться

5 ответов

Рекурсивное решение:

function combinations($arrays, $i = 0) {
    if (!isset($arrays[$i])) {
        return array();
    }
    if ($i == count($arrays) - 1) {
        return $arrays[$i];
    }

    // get combinations from subsequent arrays
    $tmp = combinations($arrays, $i + 1);

    $result = array();

    // concat each array from tmp with each element from $arrays[$i]
    foreach ($arrays[$i] as $v) {
        foreach ($tmp as $t) {
            $result[] = is_array($t) ? 
                array_merge(array($v), $t) :
                array($v, $t);
        }
    }

    return $result;
}

print_r(
    combinations(
        array(
            array('A1','A2','A3'), 
            array('B1','B2','B3'), 
            array('C1','C2')
        )
    )
);
48
ответ дан Krzysztof 21 August 2018 в 11:30
поделиться
  • 1
    как мне изменить эту функцию, если мне нужны уникальные комбинации для дублированных массивов? Например, если у меня есть массив ('A1', 'A2', 'A3'), массив ('A1', 'A2', 'A3'), массив ('C1', 'C2'), и я хочу как результат "A1, A2, C1", "A1, A3, C1" и т. д., но NO "A1, A1, C1" ? Также (если я не слишком много спрашиваю;), {«A1», «A2», «C1»} то же самое, что {«A2», «A1», «C1»}, поэтому Мне нужна только 1 комбинация? – Alex Angelico 30 May 2013 в 02:23
  • 2
    @AlexAngelico - и для кого-то другого с таким же вопросом см. Array_unique, php.net/manual/en/function.array-unique.php – Daniel Brose 4 April 2017 в 03:25

Этот код, кроме простоты, получает все комбинации из нескольких массивов и сохраняет ключи.

function get_combinations($arrays) {
    $result = array(array());
    foreach ($arrays as $property => $property_values) {
        $tmp = array();
        foreach ($result as $result_item) {
            foreach ($property_values as $property_key => $property_value) {
                $tmp[] = $result_item + array($property_key => $property_value);
            }
        }
        $result = $tmp;
    }
    return $result;
}

Пример:

Array
(
    Array
    (
        '1' => 'White',
        '2' => 'Green',
        '3' => 'Blue'
    ),
    Array
    (
        '4' =>' Small',
        '5' => 'Big'
    )
)

Вернет:

Array
(
    [0] => Array
    (
        [1] => White
        [4] =>  Small
    )
    [1] => Array
    (
        [1] => White
        [5] => Big
    )
    [2] => Array
    (
        [2] => Green
        [4] =>  Small
    )
    [3] => Array
    (
        [2] => Green
        [5] => Big
    )
    [4] => Array
    (
        [3] => Blue
        [4] =>  Small
    )
    [5] => Array
    (
        [3] => Blue
        [5] => Big
    )
)
3
ответ дан amlette 21 August 2018 в 11:30
поделиться
  • 1
    Не знаю, почему кто-то еще это сделал. Это решение отлично сработало для меня и сохранил ключи массива, как я этого хотел. +1 – Eric Seastrand 16 August 2016 в 18:46

Это декартово произведение, и я просто задал тот же вопрос не так давно . Вот алгоритм , который размещен на веб-сайте PHP .

function array_cartesian_product($arrays)
{
    $result = array();
    $arrays = array_values($arrays);
    $sizeIn = sizeof($arrays);
    $size = $sizeIn > 0 ? 1 : 0;
    foreach ($arrays as $array)
        $size = $size * sizeof($array);
    for ($i = 0; $i < $size; $i ++)
    {
        $result[$i] = array();
        for ($j = 0; $j < $sizeIn; $j ++)
            array_push($result[$i], current($arrays[$j]));
        for ($j = ($sizeIn -1); $j >= 0; $j --)
        {
            if (next($arrays[$j]))
                break;
            elseif (isset ($arrays[$j]))
                reset($arrays[$j]);
        }
    }
    return $result;
}
13
ответ дан Community 21 August 2018 в 11:30
поделиться
  • 1
    Ссылка на веб-сайт PHP, по-видимому, ничего не говорит об этой функции. Не могли бы вы привести пример его вызова? – JohnK 9 July 2014 в 01:28
  • 2
    Эта функция занимает в 2,5 раза больше времени, чем функция Lolo для обработки одного и того же массива. – Richard - Rogue Wave Limited 11 September 2014 в 17:26

Еще одна идея:

$ar = [
    'a' => [1,2,3],
    'b' => [4,5,6],
    'c' => [7,8,9]
];

$counts = array_map("count", $ar);
$total = array_product($counts);
$res = [];

$combinations = [];
$curCombs = $total;

foreach ($ar as $field => $vals) {
    $curCombs = $curCombs / $counts[$field];
    $combinations[$field] = $curCombs;
}

for ($i = 0; $i < $total; $i++) {
    foreach ($ar as $field => $vals) {
        $res[$i][$field] = $vals[($i / $combinations[$field]) % $counts[$field]];
    }
}

var_dump($res);
0
ответ дан Eugene Fedorenko 21 August 2018 в 11:30
поделиться

Я знаю, что этот вопрос старый, но сегодня у меня такая же проблема, и я решил попробовать новый генератор:

function generateCombinations(array $array) {
    foreach (array_pop($array) as $value) {
        if (count($array)) {
            foreach (generateCombinations($array) as $combination) {
                yield array_merge([$value], $combination);
            };
        } else {
            yield [$value];
        }
    }
}

foreach (generateCombinations(['a' => ['A'], 'b' => ['B'], 'c' => ['C', 'D'], 'd' => ['E', 'F', 'G']]) as $c) {
        var_dump($c);
    }

Результат:

array(4) {
[0]=>
string(1) "E"
[1]=>
string(1) "C"
[2]=>
string(1) "B"
[3]=>
string(1) "A"
}
array(4) {
[0]=>
string(1) "E"
[1]=>
string(1) "D"
[2]=>
string(1) "B"
[3]=>
string(1) "A"
}
array(4) {
[0]=>
string(1) "F"
[1]=>
string(1) "C"
[2]=>
string(1) "B"
[3]=>
string(1) "A"
}
array(4) {
[0]=>
string(1) "F"
[1]=>
string(1) "D"
[2]=>
string(1) "B"
[3]=>
string(1) "A"
}
array(4) {
[0]=>
string(1) "G"
[1]=>
string(1) "C"
[2]=>
string(1) "B"
[3]=>
string(1) "A"
}
array(4) {
[0]=>
string(1) "G"
[1]=>
string(1) "D"
[2]=>
string(1) "B"
[3]=>
string(1) "A"
}
4
ответ дан mr1031011 21 August 2018 в 11:30
поделиться
  • 1
    Когда порядок не имеет значения, это комбинация. Когда порядок имеет значение, это перестановка. В этом случае это перестановка, а не комбинация. – Pol Dellaiera 20 December 2016 в 22:01
  • 2
    это самое простое решение – clarkk 27 March 2018 в 21:04
  • 3
    есть ли способ достичь этого? array(4) { 'd' => string(1) "E" 'c' => string(1) "C" 'b' => string(1) "B" 'a' => string(1) "A" } – Glasset 29 March 2018 в 14:36
  • 4
    обходной вопрос для моего вопроса: создать массив, подобный этому ['a' => [['key' => 'a', 'value' => 'A'], ['key' => 'a', 'value' => 'n']]] – Glasset 29 March 2018 в 14:45
Другие вопросы по тегам:

Похожие вопросы: