Greifen Sie mit array_map() auf Schlüssel der ersten Ebene zu, ohne `array_keys()` aufzurufen

Lesezeit: 10 Minuten

Benutzeravatar von José Tomás Tocino
José Tomás Tocino

Gibt es eine Möglichkeit, so etwas zu tun:

$test_array = array(
    "first_key" => "first_value", 
    "second_key" => "second_value"
);

var_dump(
    array_map(
        function($a, $b) {
            return "$a loves $b";
        }, 
        array_keys($test_array), 
        array_values($test_array)
    )
);

Aber anstatt anzurufen array_keys und array_valuesdirekt vorbei an der $test_array Variable?

Die gewünschte Ausgabe ist:

array(2) {
  [0]=>
  string(27) "first_key loves first_value"
  [1]=>
  string(29) "second_key loves second_value"
}

Benutzeravatar von eis
eis

Nicht mit array_map, da es keine Schlüssel verarbeitet.

array_walk tut:

$test_array = array("first_key" => "first_value",
                    "second_key" => "second_value");
array_walk($test_array, function(&$a, $b) { $a = "$b loves $a"; });
var_dump($test_array);

// array(2) {
//   ["first_key"]=>
//   string(27) "first_key loves first_value"
//   ["second_key"]=>
//   string(29) "second_key loves second_value"
// }

Es ändert jedoch das als Parameter angegebene Array, es handelt sich also nicht genau um eine funktionale Programmierung (da Sie die Frage so gekennzeichnet haben). Wie im Kommentar erwähnt, werden dadurch nur die Werte des Arrays geändert, sodass die Schlüssel nicht die sind, die Sie in der Frage angegeben haben.

Sie könnten eine Funktion schreiben, die die oben genannten Punkte selbst behebt, wenn Sie möchten, wie folgt:

function mymapper($arrayparam, $valuecallback) {
  $resultarr = array();
  foreach ($arrayparam as $key => $value) {
    $resultarr[] = $valuecallback($key, $value);
  }
  return $resultarr;
}

$test_array = array("first_key" => "first_value",
                    "second_key" => "second_value");
$new_array = mymapper($test_array, function($a, $b) { return "$a loves $b"; });
var_dump($new_array);

// array(2) {
//   [0]=>
//   string(27) "first_key loves first_value"
//   [1]=>
//   string(29) "second_key loves second_value"
// }

  • Außer, dass Sie in diesem Fall wollen $a = "$b loves $a"um der gewünschten Ausgabe des OP zu entsprechen.

    – cmbuckley

    23. Oktober 2012 um 18:08 Uhr


  • richtig, geändert 🙂 es ist schön, wie unterschiedlich sie array_map von array_walk gemacht haben.

    – eis

    23. Oktober 2012 um 18:10 Uhr


  • Nett, danke. Um zu vermeiden, dass das ursprüngliche Array durcheinander gebracht wird, habe ich schließlich Folgendes getan (siehe meine Antwort unten).

    – José Tomás Tocino

    23. Oktober 2012 um 21:08 Uhr


  • Dies ist jedoch keine “funktionale Programmierung”. array_walk() gibt nicht das resultierende Array zurück, sondern einen booleschen Wert.

    – Mae

    14. August 2017 um 16:02 Uhr

  • @mae ja, wie ich auch in der Antwort geschrieben habe – anstatt den Wert zurückzugeben, ändert es den Parameter

    – eis

    14. August 2017 um 17:15 Uhr

Benutzeravatar von Kevin Beal
Kevin Bal

Dies ist wahrscheinlich die kürzeste und einfachste Begründung:

$states = array('az' => 'Arizona', 'al' => 'Alabama');

array_map(function ($short, $long) {
    return array(
        'short' => $short,
        'long'  => $long
    );
}, array_keys($states), $states);

// produces:
array(
     array('short' => 'az', 'long' => 'Arizona'), 
     array('short' => 'al', 'long' => 'Alabama')
)

  • Ich habe gerade festgestellt, dass die Frage ausdrücklich besagt, dass sie nicht verwendet werden soll array_keys(). Das scheint jedoch eine dumme Anforderung zu sein.

    – Kevin Beal

    12. August 2015 um 20:16 Uhr

  • Die Frage lieferte eine Lösung mit array_keys(), es wäre dumm, eine Antwort zu geben, die keinen Vorteil gegenüber der aktuellen Lösung hat (zB weniger Funktionen aufrufen).

    – Chinoto Vokro

    29. März 2016 um 14:48 Uhr

  • Die Antwort auf die ursprüngliche Frage lautet NEIN, und dies ist die am besten geeignete Lösung.

    – usoban

    4. Oktober 2016 um 14:05 Uhr

  • Diese Antwort hat die Beispieldaten und die gewünschte Ausgabe der gestellten Frage ignoriert.

    – mickmackusa

    30. Juli um 6:02 Uhr

Benutzeravatar von Nicholas Shanks
Nikolaus Shanks

Hier ist meine sehr einfache, PHP 5.5-kompatible Lösung:

function array_map_assoc(callable $f, array $a) {
    return array_column(array_map($f, array_keys($a), $a), 1, 0);
}

Der von Ihnen bereitgestellte Aufruf sollte selbst ein Array mit zwei Werten zurückgeben, dh return [key, value]. Der innere Ruf nach array_map erzeugt daher ein Array von Arrays. Dieses wird dann von wieder in ein eindimensionales Array konvertiert array_column.

Verwendungszweck

$ordinals = [
    'first' => '1st',
    'second' => '2nd',
    'third' => '3rd',
];

$func = function ($k, $v) {
    return ['new ' . $k, 'new ' . $v];
};

var_dump(array_map_assoc($func, $ordinals));

Ausgabe

array(3) {
  ["new first"]=>
  string(7) "new 1st"
  ["new second"]=>
  string(7) "new 2nd"
  ["new third"]=>
  string(7) "new 3rd"
}

Teilanwendung

Falls Sie die Funktion viele Male mit verschiedenen Arrays, aber derselben Zuordnungsfunktion verwenden müssen, können Sie eine sogenannte partielle Funktionsanwendung (bezogen auf ‘Curry‘), wodurch Sie das Datenarray nur beim Aufruf übergeben können:

function array_map_assoc_partial(callable $f) {
    return function (array $a) use ($f) {
        return array_column(array_map($f, array_keys($a), $a), 1, 0);
    };
}

...
$my_mapping = array_map_assoc_partial($func);
var_dump($my_mapping($ordinals));

Was die gleiche Ausgabe erzeugt, gegeben $func und $ordinals sind wie früher.

HINWEIS: Wenn Ihre zugeordnete Funktion die zurückgibt gleichen Schlüssel bei zwei unterschiedlichen Eingängen der zugeordnete Wert der spätere Schlüssel gewinnt. Kehren Sie das Eingabearray um und geben Sie das Ergebnis von aus array_map_assoc um früheren Schlüsseln zu erlauben, zu gewinnen. (Die zurückgegebenen Schlüssel in meinem Beispiel können nicht kollidieren, da sie den Schlüssel des Quellarrays enthalten, der wiederum eindeutig sein muss.)


Alternative

Das Folgende ist eine Variante des Obigen, die sich für manche als logischer erweisen könnte, aber PHP 5.6 erfordert:

function array_map_assoc(callable $f, array $a) {
    return array_merge(...array_map($f, array_keys($a), $a));
}

In dieser Variante sollte Ihre bereitgestellte Funktion (über die das Datenarray abgebildet wird) stattdessen ein assoziatives Array mit einer Zeile zurückgeben, dh return [key => value]. Das Ergebnis des Mappings des Callable wird dann einfach entpackt und übergeben array_merge. Wie zuvor führt die Rückgabe eines doppelten Schlüssels dazu, dass spätere Werte gewinnen.

nb Alex83690 hat in einem Kommentar darauf hingewiesen, dass using array_replace hier statt array_merge würde ganzzahlige Schlüssel beibehalten. array_replace ändert das Eingabearray nicht und ist daher sicher für Funktionscode.

Wenn Sie PHP 5.3 bis 5.5 verwenden, ist Folgendes äquivalent. Es verwendet array_reduce und die binäre + Array-Operator zum Konvertieren des resultierenden zweidimensionalen Arrays in ein eindimensionales Array unter Beibehaltung der Schlüssel:

function array_map_assoc(callable $f, array $a) {
    return array_reduce(array_map($f, array_keys($a), $a), function (array $acc, array $a) {
        return $acc + $a;
    }, []);
}

Verwendungszweck

Beide dieser Varianten würden also verwendet werden:

$ordinals = [
    'first' => '1st',
    'second' => '2nd',
    'third' => '3rd',
];

$func = function ($k, $v) {
    return ['new ' . $k => 'new ' . $v];
};

var_dump(array_map_assoc($func, $ordinals));

Beachten Sie das => Anstatt von , in $func.

Die Ausgabe ist die gleiche wie zuvor, und jede kann teilweise auf die gleiche Weise wie zuvor angewendet werden.


Zusammenfassung

Das Ziel der ursprünglichen Frage besteht darin, den Aufruf des Aufrufs so einfach wie möglich zu gestalten, auf Kosten einer komplizierteren Funktion, die aufgerufen wird. insbesondere um die Möglichkeit zu haben, das Datenarray als einzelnes Argument zu übergeben, ohne die Schlüssel und Werte aufzuteilen. Verwenden Sie die am Anfang dieser Antwort angegebene Funktion:

$test_array = ["first_key" => "first_value",
               "second_key" => "second_value"];

$array_map_assoc = function (callable $f, array $a) {
    return array_column(array_map($f, array_keys($a), $a), 1, 0);
};

$f = function ($key, $value) {
    return [$key, $key . ' loves ' . $value];
};

var_dump(array_values($array_map_assoc($f, $test_array)));

Oder wir können nur für diese Frage eine Vereinfachung zu machen array_map_assoc() Funktion, die Ausgabeschlüssel löscht, da die Frage nicht danach fragt:

$test_array = ["first_key" => "first_value",
               "second_key" => "second_value"];

$array_map_assoc = function (callable $f, array $a) {
    return array_map($f, array_keys($a), $a);
};

$f = function ($key, $value) {
    return $key . ' loves ' . $value;
};

var_dump($array_map_assoc($f, $test_array));

Die Antwort lautet also NEINSie können es nicht vermeiden anzurufen array_keysaber Sie können die Stelle wo abstrahieren array_keys wird in eine Funktion höherer Ordnung aufgerufen, was gut genug sein könnte.

  • array_column ist nur PHP 5.5+, daher ist diese Antwort nicht mit PHP 5.3 kompatibel

    – icc97

    9. Mai 2017 um 9:35 Uhr

  • Ich werde DER Typ sein. PHP 5.3 soll zum Datum von keine Voraussetzung mehr sein Dies Antworten. MEINER BESCHEIDENEN MEINUNG NACH.

    – Erutan409

    24. Juli 2018 um 13:45 Uhr

  • Ihre erste Alternativlösung ist ungültig. musst du ersetzen array_merge durch array_replace um Schlüssel zu erhalten, die ganze Zahlen wären.

    – Alex83690

    23. August 2018 um 7:35 Uhr

  • @Alex83690 Danke! Obwohl ich sagen würde, dass “ungültig” leicht irreführend ist – es ist in Ordnung, wenn Sie keine ganzzahligen Schlüssel haben (wie es in meinem eigenen Fall der Fall war).

    – Nikolaus Shanks

    23. August 2018 um 9:08 Uhr


  • Wenn einige an einer Array-Mapping-Funktion interessiert sind, die Schlüssel beibehält und gleichzeitig der Rückruf Zugriff auf Schlüssel und Wert hat und nur einen Wert zurückgeben kann (wie es eine normale Mapping-Funktion tut) anstelle eines “speziell formatierten” Werts (ein assoziatives Array mit einer Zeile), dann ist hier eine leicht modifizierte PHP 5.6-Lösung: function array_map_assoc(callable $f, array $a) { return array_merge(...array_map(function ($k, $v) use ($f) { return [ $k => $f($k, $v) ]; }, array_keys($a), $a)); }. Damit dies funktioniert, müssen die $f muss mit einer anderen Funktion umschlossen werden, die den neuen Wert abbildet [key=>new_value].

    – Ruslan Stelmachenko

    10. Februar 2019 um 2:31 Uhr


Benutzeravatar von Ostap Brehin
Ostap Brehin

$array = [
  'category1' => 'first category',
  'category2' => 'second category',
];
 
$new = array_map(function($key, $value) {
  return "{$key} => {$value}";
}, array_keys($array), $array);

Mit PHP5.3 oder höher:

$test_array = array("first_key" => "first_value", 
                    "second_key" => "second_value");

var_dump(
    array_map(
        function($key) use ($test_array) { return "$key loves ${test_array[$key]}"; },
        array_keys($test_array)
    )
);

  • Ich denke, die Anforderung war “anstatt array_keys und array_values ​​aufzurufen, die Variable $test_array direkt zu übergeben”, kann dies ohne array_keys verwendet werden?

    – eis

    5. Juni 2014 um 7:29 Uhr

Benutzeravatar von Francesco DM
Francesco DM

Ich werde noch eine weitere Lösung für das Problem mit Version 5.6 oder höher hinzufügen. Ich weiß nicht, ob es effizienter ist als die bereits großartigen Lösungen (wahrscheinlich nicht), aber für mich ist es einfach einfacher zu lesen:

$myArray = [
    "key0" => 0,
    "key1" => 1,
    "key2" => 2
];

array_combine(
    array_keys($myArray),
    array_map(
        function ($intVal) {
            return strval($intVal);
        },
        $myArray
    )
);

Verwenden strval() als Beispielfunktion in der array_mapdies erzeugt:

array(3) {
  ["key0"]=>
  string(1) "0"
  ["key1"]=>
  string(1) "1"
  ["key2"]=>
  string(1) "2"
}

Hoffentlich bin ich nicht der Einzige, der das ziemlich einfach zu verstehen findet.
array_combine schafft ein key => value Array aus einem Array von Schlüsseln und einem Array von Werten, der Rest ist ziemlich selbsterklärend.

  • Ich denke, die Anforderung war “anstatt array_keys und array_values ​​aufzurufen, die Variable $test_array direkt zu übergeben”, kann dies ohne array_keys verwendet werden?

    – eis

    5. Juni 2014 um 7:29 Uhr

Benutzeravatar von IanS
IanS

Schau hier! Es gibt eine triviale Lösung!

function array_map2(callable $f, array $a)
{
    return array_map($f, array_keys($a), $a);
}

Wie in der Frage gesagt, array_map hat bereits genau die benötigte Funktionalität. Die anderen Antworten hier verkomplizieren die Dinge ernsthaft: array_walk ist nicht funktionsfähig.

Verwendungszweck

Genau so, wie Sie es von Ihrem Beispiel erwarten würden:

$test_array = array("first_key" => "first_value", 
                    "second_key" => "second_value");

var_dump(array_map2(function($a, $b) { return "$a loves $b"; }, $test_array));

  • Die anderen Antworten machen die Dinge zu kompliziert, weil die Frage angegeben ist qrrqy_keys() sollte aus #Gründen nicht verwendet werden

    – Brad Kent

    6. Mai 2020 um 20:32 Uhr

1429080cookie-checkGreifen Sie mit array_map() auf Schlüssel der ersten Ebene zu, ohne `array_keys()` aufzurufen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy