2015-03-23 12 views
5

Ho un array associativo $assoc, e la necessità di ridurre a una stringa, in questo contestoarray_reduce() non può funzionare come "riduttore" di array associativi per PHP?

$OUT = "<row"; 
foreach($assoc as $k=>$v) $OUT.= " $k=\"$v\""; 
$OUT.= '/>'; 

Come fare in an elegant way la stessa cosa, ma utilizzando array_reduce()


Vicino lo stesso algoritmo (prestazioni inferiori e minore leggibilità) con la funzione array_walk(),

array_walk( $row, function(&$v,$k){$v=" $k=\"$v\"";} ); 
$OUT.= "\n\t<row". join('',array_values($row)) ."/>"; 

Ugly soluzione array_map() (e ancora una volta come join()riduttore):

$row2 = array_map( 
    function($a,$b){return array(" $a=\"$b\"",1);}, 
    array_keys($row), 
    array_values($row) 
); // or 
    $OUT ="<row ". join('',array_column($row2,0)) ."/>"; 

PS: a quanto pare PHP di array_reduce() non supporta gli array associativi (perché ??).

+0

array_reduce() non si preoccupa se la matrice è associativa o enumerato, o anche un mix, quindi non diffondere FUD .... o fornire un esempio genuino dove fallisce .... nota che il callback è puramente valori, che è il comportamento documentato, che non è la stessa cosa che non supporta gli array associativi –

+0

@ MarkBaker sì, la funzione è onesta su "nessun accesso all'indice corrente del valore corrente" ... E su altri linguaggi ([come Python] (https://docs.python.org/2/library/functions.html #redu ce)) usa la stessa semantica per * reduce() * ... È meglio visualizzare * reduce() * primo parametro come [attraversabile] (http://php.net/manual/en/class.traversable.php) (non un array), dove sono noti solo * current/next *. –

+2

Non è FUD. Può essere male formulato, ma array_reduce non supporta gli array associativi in ​​modo corretto o completo. Li supporta solo parzialmente, trattandoli come quelli non associativi. L'implementazione per array non associativi di PHP è in realtà un array associativo, ma dal momento che si eliminano le chiavi su array_reduce, non è molto utile quando è necessario un associativo. Questo è il punto. – Asrail

risposta

2

Innanzitutto, array_reduce() funziona con gli array associativi, ma non è possibile accedere alla chiave nella funzione di callback, ma solo al valore.

È possibile utilizzare la parola chiave use per accedere allo $result come riferimento nella chiusura come nell'esempio seguente con array_walk(). Questo sarebbe molto simile a array_reduce():

$array = array(
    'foo' => 'bar', 
    'hello' => 'world' 
); 

// Inject reference to `$result` into closure scope. 
// $result will get initialized on it's first usage. 
array_walk($array, function($key, $val) use(&$result) { 
    $result .= "$key=\"$val\""; 
}); 
echo $result; 

Btw, imo la soluzione foreach originale sembra elegante troppo. Inoltre, non ci saranno problemi di prestazioni significativi finché l'array rimarrà di piccole e medie dimensioni.

3

Io personalmente vedo nulla di sbagliato con la cosa foreach, ma se si vuole una sola espressione, la tua map frammento può essere semplificata fino a

$OUT = sprintf("<row %s/>", 
    join(" ", array_map(
     function($a, $b) { return "$a=\"$b\""; }, 
     array_keys($assoc), 
     array_values($assoc) 
))); 

Inoltre, dal momento che si sta generando XML, è meglio usare uno strumento dedicato, ad esempio:

$doc = new SimpleXMLElement("<row/>"); 
foreach($assoc as $k => $v) 
    $doc->addAttribute($k, $v); 
echo $doc->asXML(); 
7
$array = array(
    'foo' => 'bar', 
    'hello' => 'world' 
); 

$OUT = join(" ", array_reduce(array_keys($array), function($as, $a) use ($array) { 
    $as[] = sprintf('%s="%s"', $a, $array[$a]); return $as; 
}, array())); 
0

rigorosamente utilizzando array_reduce questo è il più semplice algo rithm mi viene in mente (anche entrambe le funzioni anonime sono funzioni pure):

$out = 
    '<row '. 
     array_reduce(
      array_map (
       function ($e, $k) { return [$e, $k]; }, 
       array_keys($assoc), 
       $assoc 
      ), 
      function ($props, $e) { return $props." {$e[0]}=\"{$e[1]}\""; } 
     ) 
    .' />'; 

In una linea di ...

$out = '<row '. array_reduce(array_map(function ($e, $k) { return [$e, $k]; }, array_keys($assoc), $assoc), function ($props, $e) { return $props." {$e[0]}=\"{$e[1]}\""; }).' />'; 
Problemi correlati