Producto cartesiano de N matrices

5 minutos de lectura

Producto cartesiano de N matrices
stukerr

Tengo una matriz de PHP que se parece a este ejemplo:

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

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

Y me gustaría poder producir a partir de esto una tabla con todas las combinaciones posibles de estos, pero sin repetir ninguna combinación (independientemente de su posición), así que, por ejemplo, esto generaría

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

Pero me gustaría que esto pudiera funcionar con tantas matrices diferentes como sea posible.

  • ¿Habrá Array 2, Array 3, Array N? ¿O solo dos matrices?

    – Luz plateada

    25 de marzo de 2010 a las 15:05

  • Hola, lo siento por no ser más claro, podría haber una matriz 2, una matriz 3 hasta una matriz n. Gracias.

    – stukerr

    25 de marzo de 2010 a las 15:05

  • Lo que necesita es una unión cruzada fácil en SQL, pero necesita pensar un poco en PHP

    – Luz plateada

    25 de marzo de 2010 a las 15:15

  • Da la casualidad de que esto proviene de una base de datos mySQL, todas las opciones (manzanas, peras, naranjas, steve, bob, etc.) están en un kit de tabla, una clave para otra tabla que define en qué grupo están (frutas, personas, etc.). ), ¿alguna idea de cómo podría trabajar eso en mysql?

    – stukerr

    25 de marzo de 2010 a las 15:20

1646749032 520 Producto cartesiano de N matrices
usuario187291

esto se llama “producto cartesiano”, página de manual de php en matrices http://php.net/manual/en/ref.array.php muestra algunas implementaciones (en comentarios).

y aquí hay otro más:

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);

  • Si esta función vive en una clase, es posible que desee cambiar la llamada user_func de esta manera: $c = call_user_func_array(array($this,__FUNCTION__), $_);. Además, puede dar una advertencia (no una matriz) si las matrices de entrada no son del mismo tamaño.

    – nana

    21 de agosto de 2012 a las 14:43

  • Esta es una buena solución, pero el resultado del primer cortocircuito es cierto, lo que no tiene sentido para mí. Prueba este.

    – Walf

    3 de octubre de 2014 a las 3:34


Está buscando el producto cartesiano de las matrices, y hay un ejemplo en el sitio de matrices php: http://php.net/manual/en/ref.array.php

Syom copió http://www.php.net/manual/en/ref.array.php#54979 pero lo adapté esto para convertirlo en una versión asociativa:

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;
}

Necesitaba hacer lo mismo y probé las soluciones anteriores publicadas aquí, pero no pude hacer que funcionaran. Tengo una muestra de este tipo inteligente http://www.php.net/manual/en/ref.array.php#54979. Sin embargo, su muestra no manejó el concepto de combinaciones no repetitivas. Así que incluí esa parte. Aquí está mi versión modificada, espero que ayude:

$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;
}

El resultado sería algo como esto:
manzanas – steve
manzanas – bob
peras – steve
peras – bob
naranjas – steve
naranjas – bob

Si la matriz de datos es algo como esto:

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

Luego imprimirá algo como esto:

Increíble – beneficio – Maravilloso
Increíble – oferta – Maravilloso
Increíble – recompensa – Maravilloso
Maravilloso – beneficio – Increíble
Maravilloso – oferta – Increíble
Maravilloso – recompensa – Increíble

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

no me juzgues..

1646749032 520 Producto cartesiano de N matrices
usuario187291

Creo que esto funciona, aunque después de escribirlo me di cuenta de que es bastante similar a lo que otros han puesto, pero te da una matriz en el formato solicitado. Perdón por la mala denominación de las variables.

$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;   
            }
        }
    }
}

@usuario187291

Modifiqué esto para que sea

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;
}

por lo tanto, devuelve esa matriz vacía tan importante (el mismo resultado que ninguna combinación) cuando pasa 0 argumentos.

Solo noté esto porque lo estoy usando como

$combos = call_user_func_array('array_cartesian', $array_of_arrays);

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad