2011-03-26 13 views
32

¿Alguien me puede dejar saber cómo permitir que la matriz php tenga claves duplicadas? Cuando intento insertar una clave, valor par con la clave ya existente, sobrescribe el valor de la clave anterior correspondiente con el nuevo valor. ¿Hay alguna manera de mantener ambas claves duplicadas con valores diferentes?cómo permitir llaves duplicadas en la matriz php

+26

¿Cómo accedería al valor que desea si más de uno puede tener la misma clave? –

+1

Arrays contiene una clave única. Por lo tanto, si tiene un valor múltiple para una sola clave, use una matriz anidada/multidimensional. =) eso es lo mejor que tienes. Así que solo acceda a Mike Lewis y déle la recompensa = P – PicoCreator

+0

¿Cómo distinguiría las dos teclas? ¿Cómo asociaría un valor a cualquiera de ellos y lo recuperaría? –

Respuesta

13

El objetivo de la matriz es tener claves únicas. Si desea almacenar pares de valores, entonces:

$array[] = [$value1, $value2]; 

Si tiene muchos incautos, entonces esta alternativa será más eficiente:

<?php 

if (array_key_exists($key, $array)) 
    $array[$key]['occurrences']++; 
else 
    $array[$key] = ['value'=>$value, 'occurrences'=>1]; 
51

usted podría tener una sola llave que tiene un valor de una matriz (también conocida como una matriz multidimensional), que contendría todos los elementos con esa clave dada. Un ejemplo podría ser

$countries = array(
    "United States" => array("California", "Texas"), 
    "Canada" => array("Ontario", "Quebec") 
); 
+1

Muy bien, esto soluciona un poco su problema, pero ¿y si, por casualidad, alguien necesita ordenarlo por el primer elemento de la matriz anidada? ¿Hay alguna forma razonable de hacer eso? – FanaticD

+1

cómo puedo insertar un valor a la matriz de estados unidos ..? –

+0

@MoDarwish Lo haces así: '$ countries [" United States "] [] =" Your value ";' – Refilon

27
$array[$key][] = $value; 

A continuación, acceder a él a través de:

echo $array[$key][0]; 
echo $array[$key][1]; 

Etc.

Nota que está creando una matriz de matrices utilizando este método.

+2

antes de hacer '$ array [$ key] []', asegúrate de haber creado una matriz a través de algo como 'if (! isset ($ array [$ key])) $ array [$ key] = array();'. – isra17

+2

@isra: no es necesario que lo haga. php lo hace por sí mismo;) – NikiC

+3

Sí, en este caso, no se genera ningún aviso. – Matthew

0

sólo puede lograrse a través de una matriz multidimensional

+1

¡PHP no tiene matrices multidimensionales! Son jerárquicos – symcbean

+5

@symcbean: "Como los valores de matriz pueden ser otras matrices, también son posibles árboles y matrices multidimensionales". - (http://php.net/manual/en/language.types.array.php) –

+0

@Alix Axel: esa declaración en el manual también es incorrecta. – symcbean

1

Como dice porneL, el punto central de las matrices es que las claves son únicas.

Si desea hacer referencia a varias entradas en una matriz, debe buscar los valores de la matriz.

$arr=array(
    0=>array('date'=>time(), 'ip'=>'127.0.0.1', url='index.php'), 
    1=>array('date'=>time(), 'ip'=>'192.168.1.2', url='index.php'), 
    2=>array('date'=>time(), 'ip'=>'127.0.0.1', url='other.php')); 
    $matches=retrieve_keys_matching_subkey($arr, 'ip', '127.0.0.1'); 
    foreach ($matches as $i) { 
    print implode(' ', $arr[$i]) . "\n"; 
    } 

    function retrieve_keys_matching_subkey($arr, $subkey, $value) 
    { 
    $out=array(); 
    foreach ($arr as $key=>$sub) { 
     if ($sub[$subkey]===$value) { 
      $out=$key; 
     } 
    } 
    return $out; 
    } 

Esto obviamente va a ser más eficiente si mantiene los índices. El código para esto no es trivial.

Si está trabajando con grandes conjuntos de datos, le recomiendo usar un DBMS para administrar los datos. Si eso no es práctico, entonces use una lista vinculada.

5

Te presento: Archive Array

Uso de la muestra.

<?php 
$arch = new archiveArray(); //Class setup 

// Set and overwrite the data few times 
$arch -> data = 'one'; 
$arch -> data = 2; 
$arch -> data = 'tree XD'; 

// Get the latest data, as per expected behaviour of an array object 
var_dump($arch -> data); // 'tree XD' 

// Get its previously set archived values 
var_dump($arch -> getArchived('data')); // ['one', 2] 
?> 

código de Clase

<?php 
/// 
/// An object array, which keeps an archived copy 
/// of all its previously set values. 
/// 
/// @author [email protected] 
/// 
class archiveArray { 

    public $arch_data = array(); 
    public $arch_archive = array(); 

    public function archiveArray() { 
     $arch_data = array(); 
     $arch_archive = array(); 
    } 

    public function setData($name, $value) { 
     if(array_key_exists($name, $this -> arch_data)) { 

      if(!array_key_exists($name, $this -> arch_archive)) { 
       $this -> arch_archive[ $name ] = array(); 
      } else { 
       if(!is_array($this -> arch_archive[ $name ])) { 
        $this -> arch_archive[ $name ] = array(); 
       } 
      } 

      array_push($this -> arch_archive[ $name ] , $this -> arch_data[ $name ]); 

     } 

     $this -> arch_data[ $name ] = $value; 
    } 

    public function getData($name) { 
     return $this -> arch_data[ $name ]; 
    } 

    public function getArchived($name) { 
     if(array_key_exists($name, $this -> arch_archive)) { 
      return $this -> arch_archive[ $name ]; 
     } 
     return null; 
    } 

    //!!!--- OVERLOAD functionalities START ---!!!// 
    public function __set($name, $value) {  //Uses the 'set' to create a node in the default type setting 
     $this -> setData($name, $value); 
    } 

    public function __get($name) { 
     return $this -> getData($name); 
    } 
    //!!!--- OVERLOAD functionalities END ---!!!// 
} 
?> 

TLDR: A veces se necesita un corte como este para hacer el trabajo rápido!

Su pregunta puede tener una gran controversia y va en contra de las enseñanzas de la informática. (Antes de disparar, lea todo) Pero hay casos en los que desea que esto suceda. = X

Por ejemplo, tiene una base de código, que manipula un conjunto específico de objetos de matriz. Y debido a su uso repetido (¿bucles ?, ¿recursivo?). Anula o redefine el resultado. Hasta que se dé el conjunto final.

Y cuando tienes todo hecho. De repente se da cuenta de que las especificaciones de su cliente (o su) han cambiado.En lugar de los datos finales, quiere que todos los datos estén en medio (de ahí que desee más de 1 información por clave). Y en el desafortunado caso, su sistema ya se completó de una manera tan complicada, es un dolor en! @ # $ Cambiar todo para trabajar con una matriz multidimensional fácilmente (lo que significa que reemplazar no funcionaría, especialmente si está utilizando llamadas dinámicas). Entonces, ¿qué haces?

Esto fue en realidad un escenario que encontré recientemente, pero hay un truco simple para esto, que todavía asegura que todo su código aún funcione, mientras se conservan los datos anteriores.

El resultado final, una clase que todavía se puede tratar como cualquier otro objeto. Pero ha ganado una capacidad de archivo, para mantener los datos antiguos. Se trata de una matriz multidimensional, con el índice [0] accedido directamente. Y funciona simplemente cambiando la declaración de variable con este objeto. Y cualquier cambio realizado en el parámetro del objeto, se archivaría. Para facilitar el acceso, con un cambio mínimo o nulo en todo el programa de código =)

2

No es tanto que "no puedas hacerlo". Las desventajas de una matriz con claves duplicadas se ponen de manifiesto cuando realmente intentó usarla.

  • Pierdes la capacidad de dirigir el contenido de forma individual. Para los accesos $array['duplicate'], solo verá la primera entrada.
  • Prácticamente, solo puede usar dicho objeto en un foreach que ve cada par de clave/valor independientemente de la ambigüedad.
  • Vea a continuación, también tiene que decidir cómo manejar los intentos de deshacer, o si las entradas se pueden sobrescribir en absoluto. Un modo de solo agregar es más fácil de implementar. (Y este es el caso borde de esto, donde podría tener sentido.)

De todos modos, también para tener una respuesta textualmente a la pregunta: ¿se puede utilizar la sintaxis de matrices los PHP, sino que tenga un objeto de acumulación en cambio con:

class DuplicateArray implements ArrayAccess, Iterator, Countable { 

    var $keys = array(), 
     $values = array(); 
    var $pointer = 0; 

    // initialize from array 
    function __construct($from=array()) { 
     $this->keys = array_keys($from); 
     $this->values = array_values($from); 
    } 

    // iteration 
    function count() { 
     return count($this->keys); 
    } 
    function current() { 
     return $this->values[$this->position]; 
    } 
    function key() { 
     return $this->keys[$this->position]; 
    } 
    function next() { 
     $this->position++; 
    } 
    function rewind() { 
     $this->position = 0; 
    } 
    function valid() { 
     return isset($this->keys[$this->position]); 
    } 

    // just fetches the first found entry 
    function offsetGet($key) { 
     if (($i = array_search($key, $this->keys)) !== FALSE) { 
      return $this->values[$i]; 
     } 
     else trigger_error("Undefined offset '$key'", E_USER_NOTICE); 
    } 

    // will only append new entries, not overwrite existing 
    function offsetSet($key, $value) { 
     $this->keys[] = $key; 
     $this->values[] = $value; 
    } 

    // removes first matching entry 
    function offsetUnset($key) { 
     if (($i = array_search($key, $this->keys)) !== FALSE) { 
      unset($this->keys[$i]); 
      unset($this->values[$i]); 
      // keep entries continuos for iterator 
      $this->keys = array_values($this->keys); 
      $this->values = array_values($this->values); 
     } 
    } 
    function offsetExists($key) { 
     return array_search($key, $this->keys) !== FALSE; 
    } 
} 
5

PHP no permite esto. La mejor solución es usar una matriz multidimensional. Por ejemplo ...

<?php 

    $mArray = array(array("key1" => "value1"), 
        array("key2" => "value2"), 
        array("key3" => "value3"), 
        array("key1" => "value4")); 

?> 

Observe cómo tengo duplicados de las llaves nombrado key1.

Ahora bien, si quiero llamar a cada uno de instace key1, ejecute

<?php 

    $desiredKeyName = "key1"; 

    foreach ($mArray as $aValue) { 

     foreach ($aValue as $key => $value) { 

      if ($key == $desiredKeyName) { 

       echo $value . "<br />"; 
      } 
     } 
    } 

?> 

y volverá

value1 
value4 
4

me ocurrió una solución sencilla mientras se trabaja en un proyecto personal.

Como quería un tipo de claves duplicadas, decidí almacenar mis valores de clave => en orden inverso => ​​donde el valor se convierte en la clave y la clave se convierte en el valor, de esta forma podría tener claves duplicadas que de hecho son valores. No estoy creando valores duplicados, así que funciona en este caso específico.

Así que un pequeño ejemplo:

$r = array ('banana'=>'FRUIT', 'apple'=>'FRUIT', 'broccoli'=>'VEG', 'peas'=>'VEG'); 

function get_food_group ($type, $bowl) { 
    return array_keys ($bowl, $type); 
} 

print_r (get_food_group('FRUIT', $r)); 

# PRINTS # 
# Array 
# (
# [0] => banana 
# [1] => apple 
#) 

Si vas a tener algo como:

array (
    'banana' => 'FRUIT', 
    'peach' => 'FRUIT', 
    'banana' => 'YELLOW' 
) 

entonces yo iría con otra solución.

Cuestiones relacionadas