it-swarm.com.de

PHP: Kann ich den Index in einer array_map-Funktion erhalten?

Ich verwende eine Map in PHP wie folgt:

function func($v) {
    return $v * 2;
}

$values = array(4, 6, 3);
$mapped = array_map(func, $values);
var_dump($mapped);

Ist es möglich, den Index des Werts in der Funktion abzurufen?

Wenn ich Code schreibe, der den Index benötigt, sollte ich dann eine for-Schleife anstelle einer Map verwenden?

59
Ollie Glass

Sicher können Sie mit Hilfe von array_keys():

function func($v, $k) {
    // key is now $k
    return $v * 2;
}

$values = array(4, 6, 3);
$mapped = array_map(func, $values, array_keys($values));
var_dump($mapped);
158
Aron Rotteveel

Wenn Sie eine anonyme Funktion über ein anonymes Array zuordnen, können Sie nicht auf die Schlüssel zugreifen:

array_map(
    function($val) use ($foo) { /* ... */ },
    array(key1 => val1,
          key2 => val2,
          /* ... */));

array_reduce erhält auch keinen Zugriff auf die Schlüssel. array_walk kann auf Schlüssel zugreifen, das Array wird jedoch als Referenz übergeben, was eine Umleitungsebene erfordert.

Einige Lösungen sind:

Array von Paaren

Das ist schlecht, da wir das ursprüngliche Array ändern. Außerdem erhöhen sich die Boilerplate-Aufrufe von "array ()" linear mit der Länge des Arrays:

array_map(
    function($pair) use ($foo) {
        list($key, $val) = $pair;
        /* ... */
    },
    array(array(key1, val1),
          array(key2, val2),
          /* ... */));

Temporäre Variable

Wir arbeiten mit dem ursprünglichen Array und die Boilerplate ist konstant, aber wir können eine vorhandene Variable leicht blockieren:

$i_hope_this_does_not_conflict = array(key1 => val1,
                                       key2 => val2,
                                       /* ... */);
array_map(
    function($key, $val) use ($foo) { /* ... */ },
    array_keys($i_hope_this_does_not_conflict),
    $i_hope_this_does_not_conflict);
unset($i_hope_this_does_not_conflict);

One-Shot-Funktion

Wir können den Funktionsumfang verwenden, um das Überschreiben vorhandener Namen zu verhindern, müssen jedoch eine zusätzliche Ebene von "use" hinzufügen:

call_user_func(
    function($arr) use ($foo) {
        return array_map(function($key, $val) use ($foo) { /* ... */ },
                         array_keys($arr),
                         $arr);
    },
    array(key1 => val1,
          key2 => val2,
          /* ... */));

Multi-Argument-One-Shot-Funktion

Wir definieren die Funktion, die wir im ursprünglichen Geltungsbereich abbilden, um die Boilerplate "use" zu verhindern):

call_user_func(
    function($f, $arr) {
        return array_map($f, array_keys($arr), $arr);
    },
    function($key, $val) use ($foo) { /* ... */ },
    array(key1 => val1,
          key2 => val2,
          /* ... */));

Neue Funktion

Das Interessante ist, dass unsere letzte One-Shot-Funktion eine generische Nizza-Signatur hat und sehr wie array_map aussieht. Vielleicht möchten wir dem einen Namen geben und ihn wiederverwenden:

function array_mapk($f, $arr) {
    return array_map($f, array_keys($arr), $arr);
}

Unser Anwendungscode lautet dann:

array_mapk(
    function($key, $val) use ($foo) { /* ... */ },
    array(key1 => val1,
          key2 => val2,
          /* ... */));

Indirekter Array-Spaziergang

Beim Schreiben des obigen habe ich array_walk ignoriert, da sein Argument als Referenz übergeben werden muss. Ich habe jedoch inzwischen erkannt, dass es leicht ist, dies mit call_user_func zu umgehen. Ich denke, das ist die bisher beste Version:

call_user_func(
    'array_walk',
    array(key1 => val1,
          key2 => val2,
          /* ... */),
    function($val, $key) use ($foo) { /* ... */ });
8
Warbo

In der Dropdown-Klasse fehlt ein Parameter. Ich finde es besser so:

public function options()
{
    $value = $this->value;

    $mapped = array_map(function($k, $v) use ($value) {
     return array(
        'value'    => $k,
        'display'  => $v,
        'selected' => ($value === $k),
      );
    },  array_keys($this->options), $this->options);

    return $mapped;
}
0
MatthieuH