2015-03-23 17 views
5

Mam tablicę asocjacyjną $assoc i trzeba zredukować do niego na sznurku, w tym kontekściearray_reduce() nie może działać jako "reduktor" tablicy asocjacyjnej dla PHP?

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

Jak zrobić in an elegant way to samo, ale przy użyciu array_reduce()


pobliżu ten sam algorytm (niższa wydajność i niższa czytelność) z funkcją array_walk(),

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

brzydki rozwiązanie z array_map() (i znowu join() jako reduktora):

$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: widocznie PHP array_reduce() nie obsługuje tablic asocjacyjnych (dlaczego ??).

+0

array_reduce() nie obchodzi, czy tablica jest łączne lub wyliczone, lub nawet mix, więc nie rozpowszechniaj FUD .... lub dostarczaj prawdziwego przykładu tam, gdzie zawiedzie .... zauważ, że callback to czysto wartości, co jest udokumentowanym zachowaniem, to nie to samo, co nie obsługujące tablic asocjacyjnych –

+0

@MarkBaker tak, funkcja jest uczciwa w kwestii "braku dostępu do bieżącego indeksu aktualnej wartości" ... i innych języków ([jak Python] (https://docs.python.org/2/library/functions.html #redu ce)) używają tego samego semantycznego dla * reduce() * ... Lepiej jest zobaczyć * reduce() * pierwszy parametr jako [traversalable] (http://php.net/manual/en/class.traversable.php) (nie tablica), gdzie znane są tylko * current/next *. –

+2

To nie jest FUD. Może być źle sformułowany, ale array_reduce nie obsługuje poprawnie lub całkowicie tablic asocjacyjnych. Obsługuje je tylko częściowo, traktując je jak nie stowarzyszone. Implementacja niezespolonych tablic PHP jest w rzeczywistości tablicą asocjacyjną, ale ponieważ odrzucasz klucze na array_reduce, nie jest to przydatne, gdy potrzebujesz jednego asocjatywnego. O to chodzi. – Asrail

Odpowiedz

2

Po pierwsze, działa z tablicami asocjacyjnymi, ale nie masz szansy uzyskać dostępu do klucza w funkcji wywołania zwrotnego, tylko wartość.

Możesz użyć słowa kluczowego use, aby uzyskać dostęp do $result przez odwołanie w zamknięciu, jak w poniższym przykładzie z array_walk(). To byłby bardzo podobny do 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 oryginalny rozwiązanie foreach wygląda elegancko też. Nie będzie również istotnych problemów z wydajnością, o ile tablica pozostaje mała lub średnia.

3

Osobiście widzę nic złego w rzeczy foreach, ale jeśli chcesz tylko jednego wyrażenia, Twój map urywek można uprościć do

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

Ponadto, ponieważ jesteś generowania XML, to lepiej użyć dedykowane narzędzie, na przykład:

$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

Ściśle stosując array_reduce jest to najprostszy algo rithm mogę myśleć (również obie funkcje anonimowe są czyste funkcje):

$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]}\""; } 
     ) 
    .' />'; 

w jednej linii ...

$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]}\""; }).' />';