Wie filtert man ein assoziatives Array mit Schlüsseln eines indizierten Arrays in PHP?

Lesezeit: 12 Minuten

Benutzeravatar von maček
maček

Die Callback-Funktion in array_filter() übergibt nur die Werte des Arrays, nicht die Schlüssel.

Wenn ich habe:

$my_array = array("foo" => 1, "hello" => "world");

$allowed = array("foo", "bar");

Wie lösche ich am besten alle Schlüssel in $my_array die sind nicht in der $allowed Reihe?

Gewünschte Ausgabe:

$my_array = array("foo" => 1);

  • Keine Lösung, aber ein anderer Ansatz, der nützlich sein könnte, ist $b = ['foo' => $a['foo'], 'bar' => $a['bar']] Dies wird dazu führen $b['bar'] sein null.

    – Oriadam

    2. April 2018 um 13:45 Uhr


Benutzeravatar von Vincent Savard
Vinzenz Savard

Mit array_intersect_key und array_flip:

var_dump(array_intersect_key($my_array, array_flip($allowed)));

array(1) {
  ["foo"]=>
  int(1)
}

  • Ich bin neugierig, ob dies effizienter ist als meine Lösung. Das ist definitiv eleganter 🙂

    – GWW

    23. November 2010 um 19:48 Uhr

  • @GWW, Im Allgemeinen habe ich festgestellt, dass diese Arten von Array-Funktionen schneller sind als die entsprechenden foreach Schleife (und manchmal erheblich), aber die einzige Möglichkeit, dies sicher zu wissen, besteht darin, beide mit denselben Daten zu timen.

    – Matthew

    23. November 2010 um 20:03 Uhr

  • Warum verwenden array_flip? Definieren Sie einfach die $allowed mit Schlüssel: allowed = array ( 'foo' => 1, 'bar' => 1 );

    – Yuval A.

    4. Juni 2017 um 12:55 Uhr

Benutzeravatar von Richard Turner
Richard Turner

PHP 5.6 führte einen dritten Parameter ein array_filter(), flagdie Sie einstellen können ARRAY_FILTER_USE_KEY So filtern Sie nach Schlüssel statt nach Wert:

$my_array = ['foo' => 1, 'hello' => 'world'];
$allowed  = ['foo', 'bar'];
$filtered = array_filter(
    $my_array,
    function ($key) use ($allowed) {
        // N.b. in_array() is notorious for being slow 
        return in_array($key, $allowed);
    },
    ARRAY_FILTER_USE_KEY
);

Seit PHP 7.4 Pfeilfunktionen eingeführt hat, können wir dies prägnanter machen:

$my_array = ['foo' => 1, 'hello' => 'world'];
$allowed  = ['foo', 'bar'];
$filtered = array_filter(
    $my_array,
    fn ($key) => in_array($key, $allowed),
    ARRAY_FILTER_USE_KEY
);

Das ist natürlich nicht so elegant wie array_intersect_key($my_array, array_flip($allowed))aber es bietet die zusätzliche Flexibilität, einen beliebigen Test gegen den Schlüssel durchzuführen, z $allowed könnte Regex-Muster anstelle von einfachen Zeichenfolgen enthalten.

Sie können auch verwenden ARRAY_FILTER_USE_BOTH um sowohl den Wert als auch den Schlüssel an Ihre Filterfunktion übergeben zu lassen. Hier ist ein erfundenes Beispiel, das auf dem ersten basiert, aber beachten Sie, dass ich nicht empfehlen würde, Filterregeln zu codieren $allowed Hier entlang:

$my_array = ['foo' => 1, 'bar' => 'baz', 'hello' => 'wld'];
$allowed  = ['foo' => true, 'bar' => true, 'hello' => 'world'];
$filtered = array_filter(
    $my_array,
    fn ($val, $key) => isset($allowed[$key]) && (
        $allowed[$key] === true || $allowed[$key] === $val
    ),
    ARRAY_FILTER_USE_BOTH
); // ['foo' => 1, 'bar' => 'baz']

  • Verdammt, wie die Autor dieser Funktion hätte ich nach dieser Frage suchen sollen 😉

    – Jack

    8. Juni 2015 um 8:09 Uhr


  • PHP7.4+ $filtered = array_filter( $my_array, fn ($key) => in_array($key, $allowed), ARRAY_FILTER_USE_KEY );

    – jartaud

    27. Februar 2021 um 2:38 Uhr


  • Jede Antwort, die iterierte Aufrufe von nutzt in_array() wird nicht effizienter sein als der elegantere Aufruf von array_intersect_key(). Ja, das Lookup-Array muss einmal umgedreht werden, aber da PHP sehr schnell Schlüssel-Lookups (wie z isset()), Ich erwarte in_array() in den meisten Testfällen im Staub zu lassen. Einfacher, isset() hat immer wieder bewiesen, dass es deutlich besser abschneidet in_array() bei Benchmarks. Die einzige Gefahr, der Sie sich bewusst sein müssen, besteht darin, dass die Flipping-Technik den Wert verändert – wenn Sie beispielsweise einen Float-Wert in einen Schlüssel umwandeln, wird er zu einem Int.

    – mickmackusa

    16. Januar um 5:45 Uhr


  • @mickmackusa Sie benötigen wahrscheinlich ein großes Array, damit der Unterschied für die Ausführung Ihrer Anwendung von Bedeutung ist. Normalerweise übertrumpft die Lesbarkeit die Mikrooptimierungen der Leistung. Sicherlich etwas, dessen man sich bewusst sein sollte.

    – Richard Turner

    17. Januar um 9:25 Uhr

  • Es gibt keine Einlösefunktionen für Ihre Snippets und ich würde keine davon in meinen eigenen Projekten verwenden. Die flip&intersect_key-Technik von VincentSavard ist leistungsfähiger, prägnanter, eleganter, besser lesbar und verwendet in geeigneter Weise einen vollständig nativen funktionalen Ansatz. Ich greife dich nicht an, ich vergleiche die Beiträge.

    – mickmackusa

    17. Januar um 9:43 Uhr


Hier ist eine flexiblere Lösung mit einem Verschluss:

$my_array = array("foo" => 1, "hello" => "world");
$allowed = array("foo", "bar");
$result = array_flip(array_filter(array_flip($my_array), function ($key) use ($allowed)
{
    return in_array($key, $allowed);
}));
var_dump($result);

Ausgänge:

array(1) {
  'foo' =>
  int(1)
}

In der Funktion können Sie also andere spezifische Tests durchführen.

  • Ich würde das nicht gerade als “flexibler” bezeichnen; Es fühlt sich auch viel weniger einfach an als die akzeptierte Lösung.

    – maček

    26. Januar 2013 um 21:33 Uhr

  • Ich stimme zu. Es wäre flexibler, wenn die Bedingung komplexer wäre.

    – Spule

    31. Januar 2013 um 11:25 Uhr

  • Nur vorbei, für andere Benutzer: Diese Lösung behandelt nicht den Fall, dass das $my_array doppelte Werte oder Werte hat, die keine Ganzzahlen oder Zeichenfolgen sind. Daher würde ich diese Lösung nicht verwenden.

    – Benutzer23127

    9. Juni 2014 um 17:38 Uhr

  • Ich stimme zu, dass dies flexibler ist, da Sie die Filterlogik ändern können. Zum Beispiel habe ich ein Array von unzulässigen Schlüsseln verwendet und einfach !in_array($key, $disallowed) zurückgegeben.

    – nfplee

    7. September 2014 um 13:05 Uhr


  • Es ist gefährlich anzurufen array_flip($my_array). Wenn das Array doppelte Werte enthält, wird die Größe des Arrays reduziert, da Arrays keine doppelten Schlüssel auf derselben Ebene haben können. Dieser Ansatz sollte nicht verwendet werden – er ist instabil/unzuverlässig.

    – mickmackusa

    18. Januar um 21:33 Uhr


Hier ist eine weniger flexible Alternative mit nicht gesetzt():

$array = array(
    1 => 'one',
    2 => 'two',
    3 => 'three'
);
$disallowed = array(1,3);
foreach($disallowed as $key){
    unset($array[$key]);
}

Das Ergebnis von print_r($array) Sein:

Array
(
    [2] => two
)

Dies gilt nicht, wenn Sie die behalten möchten gefiltert Werte für die spätere Verwendung, aber aufgeräumter, wenn Sie sicher sind, dass Sie dies nicht tun.

Benutzeravatar von Nicolas Zimmer
Nicolas Zimmer

Wenn Sie nach einer Methode suchen, um ein Array nach einer in Schlüsseln vorkommenden Zeichenfolge zu filtern, können Sie Folgendes verwenden:

$mArray=array('foo'=>'bar','foo2'=>'bar2','fooToo'=>'bar3','baz'=>'nope');
$mSearch="foo";
$allowed=array_filter(
    array_keys($mArray),
    function($key) use ($mSearch){
        return stristr($key,$mSearch);
    });
$mResult=array_intersect_key($mArray,array_flip($allowed));

Das Ergebnis von print_r($mResult) ist

Array ( [foo] => bar [foo2] => bar2 [fooToo] => bar3 )

Eine Anpassung dieser Antwort, die reguläre Ausdrücke unterstützt

function array_preg_filter_keys($arr, $regexp) {
  $keys = array_keys($arr);
  $match = array_filter($keys, function($k) use($regexp) {
    return preg_match($regexp, $k) === 1;
  });
  return array_intersect_key($arr, array_flip($match));
}

$mArray = array('foo'=>'yes', 'foo2'=>'yes', 'FooToo'=>'yes', 'baz'=>'nope');

print_r(array_preg_filter_keys($mArray, "/^foo/i"));

Ausgabe

Array
(
    [foo] => yes
    [foo2] => yes
    [FooToo] => yes
)

  • Danke für deine Antwort. Ich würde Ihnen das mit vorlegen stristr innerhalb der “Arbeit” der Funktion werden einige Annahmen für den Endbenutzer getroffen. Vielleicht wäre es besser, dem Benutzer zu erlauben, einen regulären Ausdruck zu übergeben; Dies würde ihnen mehr Flexibilität bei bestimmten Dingen wie Ankern, Wortgrenzen und Groß- und Kleinschreibung usw. geben.

    – maček

    2. März 2014 um 19:51 Uhr

  • Ich habe eine Anpassung Ihrer Antwort hinzugefügt, die anderen Menschen helfen könnte

    – maček

    2. März 2014 um 20:05 Uhr

  • Sie haben sicherlich recht, maček, das ist ein vielseitigerer Ansatz für Benutzer, die mit Regex vertraut sind. Vielen Dank.

    – Nicolas Zimmer

    3. März 2014 um 8:02 Uhr

  • Dies ist die richtige Antwort auf eine andere Frage. Alle Elemente aus dem Array entfernen, die nicht mit einer bestimmten Zeichenfolge beginnen Ihre Antwort ignoriert die Anforderungen in der gestellten Frage.

    – mickmackusa

    17. Januar um 10:19 Uhr

Ab PHP 5.6 können Sie die verwenden ARRAY_FILTER_USE_KEY Flagge ein array_filter:

$result = array_filter($my_array, function ($k) use ($allowed) {
    return in_array($k, $allowed);
}, ARRAY_FILTER_USE_KEY);

Andernfalls können Sie diese Funktion verwenden (von TestDummy):

function filter_array_keys(array $array, $callback)
{
    $matchedKeys = array_filter(array_keys($array), $callback);

    return array_intersect_key($array, array_flip($matchedKeys));
}

$result = filter_array_keys($my_array, function ($k) use ($allowed) {
    return in_array($k, $allowed);
});

Und hier ist eine erweiterte Version von mir, die einen Rückruf oder direkt die Tasten akzeptiert:

function filter_array_keys(array $array, $keys)
{
    if (is_callable($keys)) {
        $keys = array_filter(array_keys($array), $keys);
    }

    return array_intersect_key($array, array_flip($keys));
}

// using a callback, like array_filter:
$result = filter_array_keys($my_array, function ($k) use ($allowed) {
    return in_array($k, $allowed);
});

// or, if you already have the keys:
$result = filter_array_keys($my_array, $allowed));

Zu guter Letzt können Sie auch eine einfache verwenden foreach:

$result = [];
foreach ($my_array as $key => $value) {
    if (in_array($key, $allowed)) {
        $result[$key] = $value;
    }
}

  • Danke für deine Antwort. Ich würde Ihnen das mit vorlegen stristr innerhalb der “Arbeit” der Funktion werden einige Annahmen für den Endbenutzer getroffen. Vielleicht wäre es besser, dem Benutzer zu erlauben, einen regulären Ausdruck zu übergeben; Dies würde ihnen mehr Flexibilität bei bestimmten Dingen wie Ankern, Wortgrenzen und Groß- und Kleinschreibung usw. geben.

    – maček

    2. März 2014 um 19:51 Uhr

  • Ich habe eine Anpassung Ihrer Antwort hinzugefügt, die anderen Menschen helfen könnte

    – maček

    2. März 2014 um 20:05 Uhr

  • Sie haben sicherlich recht, maček, das ist ein vielseitigerer Ansatz für Benutzer, die mit Regex vertraut sind. Vielen Dank.

    – Nicolas Zimmer

    3. März 2014 um 8:02 Uhr

  • Dies ist die richtige Antwort auf eine andere Frage. Alle Elemente aus dem Array entfernen, die nicht mit einer bestimmten Zeichenfolge beginnen Ihre Antwort ignoriert die Anforderungen in der gestellten Frage.

    – mickmackusa

    17. Januar um 10:19 Uhr

So erhalten Sie den aktuellen Schlüssel eines Arrays bei der Verwendung array_filter

Unabhängig davon, wie ich Vincents Lösung für Mačeks Problem mag, verwendet sie nicht wirklich array_filter. Wenn Sie von einer Suchmaschine hierher gekommen sind und nach einer Möglichkeit gesucht haben, auf den Schlüssel der aktuellen Iteration darin zuzugreifen array_filter‘s Rückruf, Sie haben vielleicht nach so etwas gesucht (PHP >= 5.3):

$my_array = ["foo" => 1, "hello" => "world"];

$allowed = ["foo", "bar"];

reset($my_array ); // Unnecessary in this case, as we just defined the array, but
                   // make sure your array is reset (see below for further explanation).

$my_array = array_filter($my_array, function($value) use (&$my_array, $allowed) {
  $key = key($my_array); // request key of current internal array pointer
  next($my_array); // advance internal array pointer

  return isset($allowed[$key]);
});

// $my_array now equals ['foo' => 1]

Es übergibt das Array, das Sie filtern, als Referenz an den Callback. Wie array_filter nicht herkömmlich über das Array iteriert, indem der öffentliche interne Zeiger erhöht wird, müssen Sie es selbst vorantreiben.

Was hier wichtig ist, ist, dass Sie sicherstellen müssen, dass Ihr Array zurückgesetzt wird, sonst könnten Sie mittendrin anfangen (weil der interne Array-Zeiger dort von einem Code von Ihnen hinterlassen wurde, der zuvor ausgeführt wurde).

  • Diese Antwort ignoriert die Anforderungen und Beispieldaten des Fragestellers vollständig. Diese Antwort ist bestenfalls die richtige Antwort auf eine andere Frage … außer sie ist es nicht. $&array ist kein gültiges PHP und each() ist seit PHP7.2 veraltet und seit PHP8 vollständig entfernt.

    – mickmackusa

    17. Januar um 10:11 Uhr

  • Hallo @mickmackusa und vielen Dank für deine freundlichen und konstruktiven Worte. Als ich vor sieben Jahren diese Antwort schrieb, war PHP 8 noch nicht einmal am Horizont und each() wurde überhaupt nicht abgelehnt. Imho, der Kern meiner Antwort könnte leicht auf die Frage des Fragestellers übertragen werden, aber ich habe sie entsprechend aktualisiert, sodass sie jetzt kopiert und eingefügt werden kann, ohne dass man viel darüber nachdenken muss. Ich habe auch den kleinen Tippfehler mit den Referenzen behoben ($& => &$). Fühlen Sie sich frei, meine Antwort zu bearbeiten, wenn noch etwas darin ist, das Ihnen nicht gefällt. Prost

    – Grippe

    20. Januar um 16:29 Uhr

  • Bitte denken Sie auch daran, dass diese Frage “Wie verwende ich array_filter() zum Filtern von Array-Schlüsseln?” (siehe: stackoverflow.com/posts/4260086/revisions) und wurde gefragt, wann PHP 5.6 noch nicht so weit verbreitet sei, also das Neue ARRAY_FILTER_USE_KEY Flagge war nicht allgemein verfügbar. Alle Antworten auf SO sind Kinder ihrer Zeit und sind möglicherweise mehr als ein halbes Jahrzehnt später nicht mehr gültig, genau oder hilfreich. Ich weiß eigentlich nicht, ob jetzt veraltete Antworten aus historischen Gründen entfernt oder beibehalten werden sollten. Jemand könnte immer noch gezwungen sein, ein Projekt zu unterstützen, das eine längst veraltete Version von PHP verwendet.

    – Grippe

    20. Januar um 16:50 Uhr


  • Fragen Sie sich, wenn Sie ein Forscher wären, der nach dem “besten” Ansatz für die Umsetzung in seiner Anwendung sucht, würden Sie diese Antwort für “lesenswert” halten? Manchmal ist ihr “akademischer Wert” in einer geposteten Antwort, obwohl sie nicht optimal ist. Wenn Sie der Meinung sind, dass Ihr Beitrag für zukünftige Forscher hilfreich sein wird, behalten Sie ihn hier. Wenn Sie der Meinung sind, dass eine Seite mit 11 verschiedenen Antworten dadurch unnötig aufgebläht wird, sparen Sie sich die Zeit der Forscher, indem Sie den Beitrag löschen. Sogar jahrzehntealte Seiten müssen auf SO kuratiert werden, deshalb überwache ich neue und alte Seiten. Ich interessiere mich mehr als der durchschnittliche Benutzer für unsere Inhalte.

    – mickmackusa

    20. Januar um 21:42 Uhr


  • Ich denke, dass veraltete Antworten weiterhin verfügbar sein sollten. – für die Geschichte und auch für Leute, die vielleicht noch ALTES PHP verwenden (welche Sprache auch immer) – Leute, die zum Beispiel PHP 5.2 verwendet haben, werden wissen, wie man die Antwort an eine neue Version von PHP anpasst.

    – Emilushi

    29. Juni um 18:00 Uhr


1429090cookie-checkWie filtert man ein assoziatives Array mit Schlüsseln eines indizierten Arrays in PHP?

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

Privacy policy