2010-03-15 7 views
14

Ejemplo:interruptor de dos elementos de matriz asociativa

$arr = array(
    'apple'  => 'sweet', 
    'grapefruit' => 'bitter', 
    'pear'  => 'tasty', 
    'banana'  => 'yellow' 
); 

quiero cambiar las posiciones de pomelo y pera, por lo que la matriz se convertirá en

$arr = array(
    'apple'  => 'sweet', 
    'pear'  => 'tasty', 
    'grapefruit' => 'bitter', 
    'banana'  => 'yellow' 
) 

Conozco las claves y los valores de los elementos Quiero cambiar, ¿hay alguna manera fácil de hacer esto? ¿O requerirá un bucle + la creación de una nueva matriz?

Gracias

Respuesta

0

No hay manera fácil, sólo un bucle o una nueva definición de la matriz.

+2

Es para el uso con Drupal API forma, el orden de la matriz determina el orden se imprime cada elemento (campo). Sin embargo, también puedo usar la propiedad '#weight' para alterar el orden que parece ser más fácil. Simplemente significa iterar sobre cada campo para establecer un nuevo peso. –

+5

Estoy de acuerdo con Lex. PHP no proporciona una función nativa para intercambiar elementos de la matriz. Probablemente puedas escribir el tuyo con una combinación del resto de las funciones de la matriz y mucha paciencia, pero, honestamente, reescribir la matriz completa con un ciclo foreach es, de lejos, el método más fácil. Una función de intercambio personalizada no vale la pena el esfuerzo a menos que maneje arreglos muy grandes y, en tal caso, probablemente debería rediseñar esa parte de la lógica del código. –

+0

¿Se supone que esto es una respuesta? Bueno, tengo el mismo problema. Necesito cambiar el orden de dos elementos en una matriz – Mike

0

La matriz asociativa clásica no define ni garantiza la secuencia de elementos de ninguna manera. Hay una matriz/vector simple para eso. Si usa una matriz asociativa, se supone que necesita acceso aleatorio pero no secuencial. Para mí, estás usando una matriz assoc para tareas para las que no está hecha.

+3

Si eso fuera cierto, haría asort() cualquier otra función incorporada completamente inútil ... –

+0

si ves, escribí "matriz asociativa clásica", no "matriz asociativa php". La función asort es específica para la implementación de php. de nuevo, lo que dije es correcto, uno debería asociar matrices para el acceso aleatorio. si las personas se preocupan se ven un poco más amplias que solo PHP ... – Andrey

+0

¿Cuál es el problema de usar implementaciones PHP al codificar en PHP? ¿Escribes código PHP agnóstico? ¿Para qué? ¿Entonces puedes ejecutar tu PHP con un intérprete Perl? : -? –

-2

Las matrices en php son mapas ordenados.

$arr = array('apple'=>'sweet','grapefruit'=>'bitter',' 
pear'=>'tasty','banana'=>'yellow'); 

no significa que que el primer elemento es 'manzana' => 'dulce' y el último - 'banana' => 'amarilla' con sólo poner 'manzana' primero y 'banana' última . En realidad, 'apple' => 'sweet' será el primero y 'banana' => 'yellow' será el segundo debido al orden de clasificación alfabético ascendente.

+3

Esto solo sería cierto después de un 'ksort()'. Las matrices indexadas mantienen su orden (por ejemplo, el orden en que se inicializan los elementos de la matriz) – keithjgrant

+0

-1 de forma predeterminada, los elementos se ordenan implícitamente para el momento en que se inicializó la clave. – goat

0

Sí, estoy de acuerdo con Lex, si está utilizando una matriz asociativa para guardar datos, ¿por qué no utilizar su lógica maneja cómo se accede en lugar de depender de cómo están dispuestos en la matriz.

Si realmente quería asegurarse de que estaban en el orden correcto, trate de crear objetos de fruta y luego colóquelos en una matriz normal.

1

No hay una manera fácil de hacerlo. Esto suena como un error de lógica de diseño leve de su parte que lo ha llevado a intentar hacer esto cuando hay una mejor manera de hacer lo que sea que esté queriendo hacer. ¿Puedes decirnos por qué quieres hacer esto?

Usted dice que I know the keys and values of the elements I want to switch lo que me hace pensar que lo que realmente quiere es una función de clasificación ya que puede acceder fácilmente a los elementos adecuados en cualquier momento que quiera.

$value = $array[$key]; 

Si ese es el caso, entonces yo usaría sort(), ksort() o una de las muchas otras funciones de clasificación para obtener la matriz de la forma en que desea. Incluso puede usar usort() a Sort an array by values using a user-defined comparison function.

Aparte de eso, puede usar array_replace() si alguna vez necesita intercambiar valores o claves.

2

si la matriz proviene de la base de datos, agregue un campo sort_order para que siempre pueda estar seguro en qué orden están los elementos en la matriz.

1

Esto puede o no ser una opción dependiendo de su caso de uso particular, pero si inicializa su matriz con valores nulos con las claves apropiadas antes de llenarlo con datos, puede establecer los valores en cualquier orden y el original Se mantendrá el orden de las llaves.Así que en lugar de elementos de intercambio, puede evitar la necesidad de cambiar por completo:

$arr = array('apple' => null, 
      'pear' => null, 
      'grapefruit' => null, 
      'banana' => null); 

...

$arr['apple'] = 'sweet'; 
$arr['grapefruit'] = 'bitter'; // set grapefruit before setting pear 
$arr['pear'] = 'tasty'; 
$arr['banana'] = 'yellow'; 
print_r($arr); 

>>> Array 
(
    [apple] => sweet 
    [pear] => tasty 
    [grapefruit] => bitter 
    [banana] => yellow 
) 
1

No sabe con certeza si esto fue mencionado, pero, la razón de que esto es difícil es porque no está indexado toma

Repasemos:

$arrOrig = array(
    'fruit'=>'pear', 
    'veg'=>'cucumber', 
    'tuber'=>'potato' 
); 

obtener las claves:

$arrKeys = array_keys($arrOrig); 
print_r($arrKeys); 
Array(
[0]=>fruit 
[1]=>veg 
[2]=>tuber 
) 

obtener los valores:

$arrVals = array_values($arrOrig); 
print_r($arrVals); 
Array(
    [0]=>pear 
    [1]=>cucumber 
    [2]=>potato 
) 

Ahora tienes 2 arrays de tipo numérico. Cambie los índices de los que desea intercambiar y luego vuelva a leer la otra matriz en el orden de la matriz numérica modificada. Digamos que queremos intercambiar 'fruta' y 'verduras':

$arrKeysFlipped = array_flip($arrKeys); 
print_r($arrKeysFlipped); 
Array (
[fruit]=>0 
[veg]=>1 
[tuber]=>2 
) 
$indexFruit = $arrKeysFlipped['fruit']; 
$indexVeg = $arrKeysFlipped['veg']; 
$arrKeysFlipped['veg'] = $indexFruit; 
$arrKeysFlipped['fruit'] = $indexVeg; 
print_r($arrKeysFlipped); 
Array (
[fruit]=>1 
[veg]=>0 
[tuber]=>2 
) 

Ahora, puede intercambiar hacia atrás la matriz:

$arrKeys = array_flip($arrKeysFlipped); 
print_r($arrKeys); 
Array (
[0]=>veg 
[1]=>fruit 
[2]=>tuber 
) 

Ahora, se puede construir una matriz pasando a través de la matriz oringal en el 'orden' de las teclas reorganizadas.

$arrNew = array(); 
foreach($arrKeys as $index=>$key) { 
    $arrNew[$key] = $arrOrig[$key]; 
} 
print_r($arrNew); 
Array (
[veg]=>cucumber 
[fruit]=>pear 
[tuber]=>potato 
) 

No he probado esto, pero esto es lo que esperaría. ¿Esto al menos proporciona algún tipo de ayuda? Buena suerte :)

Usted podría poner esto en una función $arrNew = array_swap_assoc($key1,$key2,$arrOld);

<?php 
if(!function_exists('array_swap_assoc')) { 
    function array_swap_assoc($key1='',$key2='',$arrOld=array()) { 
     $arrNew = array(); 
     if(is_array($arrOld) && count($arrOld) > 0) { 
      $arrKeys = array_keys($arrOld); 
      $arrFlip = array_flip($arrKeys); 
      $indexA = $arrFlip[$key1]; 
      $indexB = $arrFlip[$key2]; 
      $arrFlip[$key1]=$indexB; 
      $arrFlip[$key2]=$indexA; 
      $arrKeys = array_flip($arrFlip); 
      foreach($arrKeys as $index=>$key) { 
      $arrNew[$key] = $arrOld[$key]; 
      } 
     } else { 
      $arrNew = $arrOld; 
     } 
     return $arrNew; 
    } 
} 
?> 

ADVERTENCIA: Por favor, probar y depurar antes de usarlo solo - no se han realizado pruebas en absoluto.

16

Sólo un poco más corto y menos complicada que la solución de arcaneerudite:

<?php 
if(!function_exists('array_swap_assoc')) { 
    function array_swap_assoc($key1, $key2, $array) { 
     $newArray = array(); 
     foreach ($array as $key => $value) { 
      if ($key == $key1) { 
       $newArray[$key2] = $array[$key2]; 
      } elseif ($key == $key2) { 
       $newArray[$key1] = $array[$key1]; 
      } else { 
       $newArray[$key] = $value; 
      } 
     } 
     return $newArray; 
    } 
} 

$array = $arrOrig = array(
    'fruit' => 'pear', 
    'veg' => 'cucumber', 
    'tuber' => 'potato', 
    'meat' => 'ham' 
); 

$newArray = array_swap_assoc('veg', 'tuber', $array); 

var_dump($array, $newArray); 
?> 

probado y funciona bien

+0

+1, pero explotará si existe un índice y el otro no. – Matthew

+0

@Mathew: De hecho, pero después de solucionar este problema, serviría bien al propósito deseado. – Mike

+0

+1, esto parece ser perfecto para intercambiar elementos de matrices grandes. Para intercambios pequeños, simples, de dos elementos, preferiría mucho más una [solución directa] (http://stackoverflow.com/a/11298344/1469208). :] – trejder

0

Aquí hay dos soluciones. El primero es más largo, pero no crea una matriz temporal, por lo que ahorra memoria. El segundo probablemente se ejecuta más rápido, pero utiliza más memoria:

function swap1(array &$a, $key1, $key2) 
{ 
    if (!array_key_exists($key1, $a) || !array_key_exists($key2, $a) || $key1 == $key2) return false; 

    $after = array(); 
    while (list($key, $val) = each($a)) 
    { 
    if ($key1 == $key) 
    { 
     break; 
    } 
    else if ($key2 == $key) 
    { 
     $tmp = $key1; 
     $key1 = $key2; 
     $key2 = $tmp; 
     break; 
    } 
    } 

    $val1 = $a[$key1]; 
    $val2 = $a[$key2]; 

    while (list($key, $val) = each($a)) 
    { 
    if ($key == $key2) 
     $after[$key1] = $val1; 
    else 
     $after[$key] = $val; 
    unset($a[$key]); 
    } 

    unset($a[$key1]); 
    $a[$key2] = $val2; 

    while (list($key, $val) = each($after)) 
    { 
    $a[$key] = $val; 
    unset($after[$key]); 
    } 

    return true; 
} 

function swap2(array &$a, $key1, $key2) 
{  
    if (!array_key_exists($key1, $a) || !array_key_exists($key2, $a) || $key1 == $key2) return false; 

    $swapped = array(); 

    foreach ($a as $key => $val) 
    { 
    if ($key == $key1) 
     $swapped[$key2] = $a[$key2]; 
    else if ($key == $key2) 
     $swapped[$key1] = $a[$key1]; 
    else 
     $swapped[$key] = $val; 
    } 

    $a = $swapped; 

    return true; 
} 
3

Ésta es mi versión de la función de intercambio:

function array_swap_assoc(&$array,$k1,$k2) { 
    if($k1 === $k2) return; // Nothing to do 

    $keys = array_keys($array); 
    $p1 = array_search($k1, $keys); 
    if($p1 === FALSE) return; // Sanity check...keys must exist 

    $p2 = array_search($k2, $keys); 
    if($p2 === FALSE) return; 

    $keys[$p1] = $k2; // Swap the keys 
    $keys[$p2] = $k1; 

    $values = array_values($array); 

    // Swap the values 
    list($values[$p1],$values[$p2]) = array($values[$p2],$values[$p1]); 

    $array = array_combine($keys, $values); 
} 
+0

Funciona bien gracias ! – NZSteve

0

fwiw que aquí hay una función para intercambiar dos elementos adyacentes para implementar moveUp() o moveDown() en una matriz asociativa sin foreach()

/** 
* @param array $array  to modify 
* @param string $key  key to move 
* @param int $direction +1 for down | -1 for up 
* @return $array 
*/ 
protected function moveInArray($array, $key, $direction = 1) 
{ 
    if (empty($array)) { 
     return $array; 
    } 
    $keys = array_keys($array); 
    $index = array_search($key, $keys); 
    if ($index === false) { 
     return $array; // not found 
    } 
    if ($direction < 0) { 
     $index--; 
    } 
    if ($index < 0 || $index >= count($array) - 1) { 
     return $array; // at the edge: cannot move 
    } 

    $a   = $keys[$index]; 
    $b   = $keys[$index + 1]; 
    $result  = array_slice($array, 0, $index, true); 
    $result[$b] = $array[$b]; 
    $result[$a] = $array[$a]; 
    return array_merge($result, array_slice($array, $index + 2, null, true)); 
} 
-1

Escribí una función con un propósito más general, con este problema en mente.

  1. matriz con claves conocidas
  2. especificar el orden de las claves en una segunda matriz (array de llaves $ para indicar posición clave)

función order_array ($ matriz, $ orden) {

foreach (array_keys($array) as $k => $v) { 
     $keys[++$k] = $v; 
    } 
    for ($i = 1; $i <= count($array); $i++) { 
     if (isset($order[$i])) { 
      unset($keys[array_search($order[$i], $keys)]); 
     } 
     if ($i === count($array)) { 
        array_push($keys, $order[$i]); 
       } else { 
        array_splice($keys, $i-1, 0, $order[$i]); 
       } 
      } 
     } 
     foreach ($keys as $key) { 
      $result[$key] = $array[$key]; 
     } 
     return $result; 
    } else { 
     return false; 
    } 
} 

$order = array(1 => 'item3', 2 => 'item5'); 
$array = array("item1" => 'val1', "item2" => 'val2', "item3" => 'val3', "item4" => 'val4', "item5" => 'val5'); 

print_r($array); -> Array ([item1] => val1 [item2] => val2 [item3] => val3 [item4] => val4 [item5] => val5) 

print_r(order_array($array, $order)); -> Array ([item3] => val3 [item5] => val5 [item1] => val1 [item2] => val2 [item4] => val4) 

espero que esto es relevante/útil para alguien

0

Hay una manera fácil:

$sourceArray = array(
    'apple'  => 'sweet', 
    'grapefruit' => 'bitter', 
    'pear'  => 'tasty', 
    'banana'  => 'yellow' 
); 
// set new order 
$orderArray = array(
    'apple'  => '', //this values would be replaced 
    'pear'  => '', 
    'grapefruit' => '', 
    //it is not necessary to touch all elemets that will remains the same 
); 
$result = array_replace($orderArray, $sourceArray); 
print_r($result); 

y se obtiene:

$result = array(
    'apple'  => 'sweet', 
    'pear'  => 'tasty', 
    'grapefruit' => 'bitter', 
    'banana'  => 'yellow' 
) 
Cuestiones relacionadas