PHP 2D Array выводит все комбинации

У меня была эта проблема, изгибающая мой разум некоторое время (холодная голова тоже не помогает!), В основном у меня есть массив PHP, который выглядит как этот пример:

$array[0][0] = 'apples';
$array[0][1] = 'pears';
$array[0][2] = 'oranges';

$array[1][0] = 'steve';
$array[1][1] = 'bob';

И я хотел бы получить из этого таблицу со всеми возможными комбинациями из них, но без повторения каких-либо комбинаций (независимо от их положения), поэтому, например, это выведет

Array 0            Array 1
apples             steve
apples             bob
pears              steve
pears              bob

Но я хотел бы, чтобы это могло работать с как можно большим количеством различных массивов.


person stukerr    schedule 25.03.2010    source источник
comment
Будет ли Массив 2, Массив 3, Массив N? Или только два массива?   -  person Silver Light    schedule 25.03.2010
comment
Привет, извините, что не прояснил, может быть массив 2, массив 3 до массива n. Спасибо.   -  person stukerr    schedule 25.03.2010
comment
Что вам нужно, так это перекрестное соединение, которое легко сделать в SQL, но нужно немного подумать в PHP.   -  person Silver Light    schedule 25.03.2010
comment
Поскольку это происходит из базы данных mySQL, все параметры (яблоки, груши, апельсины, стив, боб и т. д.) в одном наборе таблиц являются ключом к другой таблице, определяющей, в какой группе они находятся (фрукты, люди и т. ), какие-нибудь идеи, как я мог бы работать с этим в mysql?   -  person stukerr    schedule 25.03.2010
comment
дубликат: stackoverflow.com/questions/2516599 /   -  person Foo Bah    schedule 09.02.2011


Ответы (9)


это называется "декартовым произведением", справочная страница php по массивам http://php.net/manual/en/ref.array.php показывает некоторые реализации (в комментариях).

и вот еще один:

function array_cartesian() {
    $_ = func_get_args();
    if(count($_) == 0)
        return array(array());
    $a = array_shift($_);
    $c = call_user_func_array(__FUNCTION__, $_);
    $r = array();
    foreach($a as $v)
        foreach($c as $p)
            $r[] = array_merge(array($v), $p);
    return $r;
}

$cross = array_cartesian(
    array('apples', 'pears',  'oranges'),
    array('steve', 'bob')
);

print_r($cross);
person user187291    schedule 25.03.2010
comment
Если эта функция находится в классе, вы можете изменить вызов user_func следующим образом: $c = call_user_func_array(array($this,__FUNCTION__), $_);. Кроме того, он может выдать предупреждение (не массив), если входные массивы не имеют одинакового размера. - person Nanne; 21.08.2012
comment
Это хорошее решение, но результат первого короткого замыкания правдив, что для меня не имеет смысла. Попробуйте этот. - person Walf; 03.10.2014

Вы ищете декартово произведение массивов, и на сайте массивов php есть пример: http://php.net/manual/en/ref.array.php

person Foo Bah    schedule 09.02.2011

Syom скопировал http://www.php.net/manual/en/ref.array.php#54979, но я адаптировал его, чтобы он стал ассоциативной версией:

function array_cartesian($arrays) {
  $result = array();
  $keys = array_keys($arrays);
  $reverse_keys = array_reverse($keys);
  $size = intval(count($arrays) > 0);
  foreach ($arrays as $array) {
    $size *= count($array);
  }
  for ($i = 0; $i < $size; $i ++) {
    $result[$i] = array();
    foreach ($keys as $j) {
      $result[$i][$j] = current($arrays[$j]);
    }
    foreach ($reverse_keys as $j) {
      if (next($arrays[$j])) {
        break;
      }
      elseif (isset ($arrays[$j])) {
        reset($arrays[$j]);
      }
    }
  }
  return $result;
}
person chx    schedule 20.01.2012

Мне нужно было сделать то же самое, и я попробовал предыдущие решения, опубликованные здесь, но не смог заставить их работать. Я получил образец от этого умного парня http://www.php.net/manual/en/ref.array.php#54979. Однако в его образце не использовалась концепция отсутствия повторяющихся комбинаций. Поэтому я включил эту часть. Вот моя модифицированная версия, надеюсь поможет:

$data = array(
        array('apples', 'pears',  'oranges'),
        array('steve', 'bob')
    );

    $res_matrix = $this->array_cartesian_product( $data );

    foreach ( $res_matrix as $res_array )
    {
        foreach ( $res_array as $res )
        {
            echo $res . " - ";
        }
        echo "<br/>";
    }


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 );
    $res_index = 0;
    for ( $i = 0; $i < $size; $i++ )
    {
        $is_duplicate = false;
        $curr_values  = array();
        for ( $j = 0; $j < $sizeIn; $j++ )
        {
            $curr = current( $arrays[$j] );
            if ( !in_array( $curr, $curr_values ) )
            {
                array_push( $curr_values , $curr ); 
            }
            else
            {
                $is_duplicate = true;
                break;
            }
        }
        if ( !$is_duplicate )
        {
            $result[ $res_index ] = $curr_values;
            $res_index++;
        }
        for ( $j = ( $sizeIn -1 ); $j >= 0; $j-- )
        {
            $next = next( $arrays[ $j ] );
            if ( $next )
            {
                break;
            }
            elseif ( isset ( $arrays[ $j ] ) )
            {
                reset( $arrays[ $j ] );
            }
        }
    }
    return $result;
}

Результат будет примерно таким:
яблоки - стив
яблоки - боб
груши - стив
груши - боб
апельсины - стив
апельсины - боб

Если у вас массив данных выглядит примерно так:

  $data = array(
        array('Amazing', 'Wonderful'),
        array('benefit', 'offer', 'reward'),
        array('Amazing', 'Wonderful')
    );

Затем он напечатает что-то вроде этого:

Удивительно - польза - Замечательно
Удивительно - предложение - Замечательно
Удивительно - вознаграждение - Замечательно
Замечательно - преимущество - Удивительно
Замечательно - предложение - Удивительно
Замечательно - награда - Удивительно

person Sergio    schedule 22.05.2013

foreach($parentArray as $value) {
    foreach($subArray as $value2) {
        $comboArray[] = array($value, $value2); 
    }
}

Не суди меня..

person Dalton Conley    schedule 09.02.2011

Я думаю, что это работает - хотя после написания я понял, что это очень похоже на то, что вставили другие, но это дает вам массив в запрошенном формате. Извините за плохое имя переменной.

$output = array();
combinations($array, $output);
print_r($output);

function combinations ($array, & $output, $index = 0, $p = array()) {
    foreach ( $array[$index] as $i => $name ) {
        $copy = $p;
        $copy[] = $name;
        $subIndex = $index + 1;
        if (isset( $array[$subIndex])) {
            combinations ($array, $output, $subIndex, $copy);
        } else {
            foreach ($copy as $index => $name) {
                if ( !isset($output[$index])) {
                    $output[$index] = array();   
                }
                $output[$index][] = $name;   
            }
        }
    }
}
person Tom Haigh    schedule 25.03.2010

@user187291

Я изменил это, чтобы быть

function array_cartesian() {
    $_ = func_get_args();
    if (count($_) == 0)
        return array();
    $a = array_shift($_);
    if (count($_) == 0)
        $c = array(array());
    else
        $c = call_user_func_array(__FUNCTION__, $_);
    $r = array();
    foreach($a as $v)
        foreach($c as $p)
            $r[] = array_merge(array($v), $p);
    return $r;
}

поэтому он возвращает этот очень важный пустой массив (тот же результат, что и без комбинаций), когда вы передаете 0 аргументов.

Только заметил это, потому что я использую его как

$combos = call_user_func_array('array_cartesian', $array_of_arrays);
person Walf    schedule 20.01.2011

Пришлось составлять комбинации из вариантов товара. Это решение использует рекурсию и работает с 2D-массивом:

function options_combinations($options) {
    $result = array();
    if (count($options) <= 1) {
        $option = array_shift($options);
        foreach ($option as $value) {
            $result[] = array($value);
        }
    } else {
        $option = array_shift($options);
        $next_option = options_combinations($options);
        foreach ($next_option as $next_value) {
            foreach ($option as $value) {
                $result[] = array_merge($next_value, array($value));
            }
        }
    }
    return $result;
}

$options = [[1,2],[3,4,5],[6,7,8,9]];
$c = options_combinations($options);
foreach ($c as $combination) {
    echo implode(' ', $combination)."\n";
}
person Mark Shabalin    schedule 06.02.2017

Элегантная реализация на основе встроенной функции Python itertools.product

function direct_product(array ...$arrays)
{
    $result = [[]];
    foreach ($arrays as $array) {
        $tmp = [];
        foreach ($result as $x) {
            foreach ($array as $y) {
                $tmp[] = array_merge($x, [$y]);
            }
        }
        $result = $tmp;
    }
    return $result;
}
person mpyw    schedule 10.05.2017