2011-03-26 4 views
32

Qualcuno potrebbe farmi sapere come consentire all'array php di avere chiavi duplicate. Quando provo a inserire una chiave, coppia di valori con chiave già esistente sovrascrive il valore della chiave precedente corrispondente con il nuovo valore. C'è un modo per mantenere entrambe le chiavi duplicate con valori diversi?come consentire chiavi duplicate nell'array php

+26

Come si accede al valore desiderato se più di uno può avere la stessa chiave? –

+1

Le matrici contengono una chiave univoca. Quindi se si ha più valore per una singola chiave, utilizzare una matrice nidificata/multidimensionale. =) questo è il meglio che hai Quindi, solo una risposta [t Mike Lewis rispondi e digli la taglia = P – PicoCreator

+0

Come distinguere tra le due chiavi? Come associare un valore a qualcuno di essi e recuperarlo? –

risposta

13

L'intero punto dell'array deve avere chiavi univoche. Se si desidera memorizzare coppie di valori, quindi:

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

Se si dispone di molti gonzi, allora questa alternativa sarà più efficiente:

<?php 

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

si potrebbe avere una sola chiave che ha un valore di una matrice (ovvero un array multidimensionale), che conterrebbe tutti gli elementi con quella chiave data. Un esempio potrebbe essere

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

Va bene, questo tipo risolve il suo problema, ma cosa succede se, per caso, qualcuno avrebbe bisogno di ordinarlo dal primo elemento dell'array nidificato? C'è un modo ragionevole per farlo? – FanaticD

+1

come posso inserire un valore nell'array degli Stati Uniti ..? –

+0

@MoDarwish Lo fai in questo modo: '$ countries [" Stati Uniti "] [] =" Il tuo valore ";' – Refilon

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

È quindi accedervi tramite:

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

Ecc

Nota si crea un array di array utilizzando questo metodo.

+2

prima di fare '$ array [$ key] []', assicurati di aver creato un array tramite qualcosa come 'if (! isset ($ array [$ key])) $ array [$ key] = array();'. – isra17

+2

@isra: non c'è bisogno di farlo. php lo fa da solo;) – NikiC

+3

Sì, in questo caso non viene generato alcun avviso. – Matthew

0

può essere raggiunto solo attraverso una matrice multidimensionale

+1

PHP non ha matrici multidimensionali! Sono gerarchici – symcbean

+5

@symcbean: "Poiché i valori dell'array possono essere altri array, sono possibili anche alberi e matrici multidimensionali." - (http://php.net/manual/en/language.types.array.php) –

+0

@Alix Axel: anche questa affermazione nel manuale è errata. – symcbean

1

Come dice porneL, il punto di array è che le chiavi sono unici.

Se si desidera fare riferimento a più voci in un array, è necessario cercare i valori dell'array.

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

Questo ovviamente sarà più efficiente se si mantengono gli indici. Il codice per questo non è banale.

Se si lavora con set di dati di grandi dimensioni, si consiglia vivamente di utilizzare un DBMS per gestire i dati. Se ciò non è pratico, quindi utilizzare una lista collegata.

5

vi presento: Archivio Array

utilizzo di esempio.

<?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] 
?> 

Codice classe

<?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 volte hai bisogno di un hack come questo per ottenere il lavoro fatto in fretta!

La sua domanda può avere forti polemiche e va contro gli insegnamenti dell'informatica. (prima di scattare, leggi tutto) Ma ci sono casi in cui vuoi che ciò accada. = X

Ad esempio, si dispone di una base di codice che manipola un set specificato di oggetti di matrice. E a causa del suo uso ripetuto (loop ?, ricorsivo?). Sostituisce o ridefinisce il risultato. Fino al set finale è dato.

E quando tutto ha finito. Improvvisamente ti rendi conto che le specifiche del tuo cliente (o del tuo) sono cambiate.Invece dei dati finali, vuoi ogni singolo dato intermedio (quindi vuoi più di 1 dato per chiave). E nel caso sfortunato, il tuo sistema era già stato completato in un modo così complicato, è un dolore nel! @ # $ Cambiare tutto per lavorare con array multidimensionale facilmente (il che significa che la sostituzione non funzionerebbe, specialmente se stai usando chiamate dinamiche). Quindi cosa fai> ??

Questo era in realtà uno scenario che incontro di recente, ma c'è un semplice hack per questo, che garantisce ancora tutto il codice ancora funzionante, pur mantenendo i vecchi dati.

Il risultato finale, una classe che può ancora essere trattata come qualsiasi altro oggetto. Ma ha acquisito una capacità di archiviazione, per conservare i vecchi dati. È un array multidimensionale, con l'indice [0] a cui si accede direttamente. E funziona semplicemente cambiando la dichiarazione delle variabili con questo oggetto. E qualsiasi modifica apportata al parametro dell'oggetto, verrebbe archiviata. Per un facile accesso, con modifica minima o nulla nell'intero programma di codice =)

2

Non è tanto che "non puoi farlo". Gli svantaggi di un array con chiavi duplicate diventano evidenti quando in realtà si tenta di usarlo.

  • Si perde la possibilità di indirizzare i contenuti singolarmente. Per gli accessi $array['duplicate'] vedrai sempre la prima voce.
  • Quindi in pratica è possibile utilizzare tale oggetto solo in un foreach che vede ciascuna coppia chiave/valore indipendentemente dall'ambiguità.
  • Vedere di seguito, è inoltre necessario decidere come gestire i tentativi non impostati o se le voci possono essere sovrascritte. Una modalità di solo aggiunta è la più semplice da implementare. (E questo è il caso egde in cui potrebbe avere un senso.)

In ogni caso, per avere anche una risposta alla lettera alla domanda: è possibile utilizzare la sintassi di matrice phps ma avere un oggetto accumulo invece 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 non consente questo. La soluzione migliore è utilizzare un array multidimensionale. Per esempio ...

<?php 

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

?> 

Notate come ho chiavi duplicate nome key1.

Ora, se voglio chiamare ogni instace di key1, eseguire

<?php 

    $desiredKeyName = "key1"; 

    foreach ($mArray as $aValue) { 

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

      if ($key == $desiredKeyName) { 

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

?> 

e tornerà

value1 
value4 
4

mi si avvicinò con una soluzione semplice mentre si lavora su un progetto personale.

Poiché volevo una sorta di chiavi duplicate, ho deciso di memorizzare il mio array chiave => valori in un valore di ordine inverso => ​​chiave dove il valore diventa la chiave e la chiave diventa il valore, in questo modo potrei avere chiavi duplicate che in realtà sono valori. Non sto creando valori duplicati quindi funziona in questo caso specifico.

Quindi un piccolo esempio:

$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 
#) 

Se stai per avere qualcosa di simile:

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

Poi vorrei andare con un'altra soluzione.