mapreduce — array_reduce () не может работать в качестве ассоциативного массива & quot; reducer & quot; для PHP?

У меня есть ассоциативный массив $assocи нужно свести к нему строку, в этом контексте

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

Как сделать элегантно то же самое, но используя array_reduce()


Почти тот же алгоритм (низкая производительность и разборчивость) с array_walk() функция,

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

уродливый решение с array_map() (и опять join() как редуктор):

  $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: видимо PHP array_reduce() не поддерживает ассоциативные массивы (Зачем??).

8

Решение

Первый, array_reduce() работает с ассоциативными массивами, но у вас нет возможности получить доступ к ключу в функции обратного вызова, только к значению.

Вы могли бы использовать use ключевое слово для доступа к $result по ссылке в закрытии, как в следующем примере с array_walk(), Это было бы очень похоже на 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;

Кстати, Imo ваше оригинальное решение foreach выглядит элегантно тоже. Также не будет существенных проблем с производительностью, пока массив остается от маленького до среднего размера.

6

Другие решения

$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()));
9

Лично я не вижу в этом ничего плохого, но если вы хотите одно выражение, ваше map фрагмент может быть упрощен до

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

Кроме того, поскольку вы генерируете XML, лучше использовать специальный инструмент, например:

$doc = new SimpleXMLElement("<row/>");
foreach($assoc as $k => $v)
$doc->addAttribute($k, $v);
echo $doc->asXML();
4

Вы можете подготовить свой входной массив, используя массив ломоть и использовать array_reduce следующим образом:

$a = ["a" => 123, "b" => 234, "c" => 55];

echo array_reduce(
array_chunk($a, 1, true),
function ($r, $i) {
return $r . key($i) ." = ". current($i) . PHP_EOL;
}, "");

покажет — идеально подходит для представления массива как текста:

a = 123
b = 234
c = 55

array_chunk создаст массив из отдельных записей ассоциативного массива. пожалуйста, обратите внимание, что это, вероятно, не самое эффективное решение — просто довольно короткое.

1

Если вы настроены на array_reduceи значения вашего массива уникальны, вы можете получить доступ к ключу, передав ассоциативный массив в функцию обратного вызова и используя array_search,

// Pass $assoc to your anonymous function and use array_search to get the key.
$OUT .= array_reduce($assoc, function($o, $v) use($assoc) {
return sprintf('%s %s="%s"', $o, array_search($v, $assoc), $v);
}, '');

Лично я чувствую, что array_map а также join будет более эффективным в этой ситуации.

$OUT .= join(' ', array_map(function($v, $k){
return sprintf('%s="%s"', $k, $v);
}, $assoc, array_keys($assoc)));
1

Строго используя array_reduce это самый простой алгоритм, который я могу себе представить (обе анонимные функции являются чистыми функциями):

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

В одну строку …

$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]}\""; }).' />';
0
$ar = array(
array("month"=>'8', "revenue"=>300),
array("month"=>'2',"revenue"=>500),
array("month"=>'10',"revenue"=>100),
array("month"=>'3',"revenue"=>200),
array("month"=>'5',"revenue"=>600)
);

// where $a stores the result and $b is the new element of the array to add
function reduce_target_ar($a,$b){
return $a + $b['revenue'];
}

$sum = array_reduce($ar,"reduce_target_ar");

echo $sum;
0
По вопросам рекламы [email protected]