Gruppieren Sie Zeilen in einem assoziativen Array von assoziativen Arrays nach Spaltenwert und bewahren Sie die ursprünglichen Schlüssel der ersten Ebene

Lesezeit: 7 Minuten

Benutzeravatar von Anson Kao
Anson Kao

Ich habe ein Array von Subarrays im folgenden Format:

[
    'a' => ['id' => 20, 'name' => 'chimpanzee'],
    'b' => ['id' => 40, 'name' => 'meeting'],
    'c' => ['id' => 20, 'name' => 'dynasty'],
    'd' => ['id' => 50, 'name' => 'chocolate'],
    'e' => ['id' => 10, 'name' => 'bananas'],
    'f' => ['id' => 50, 'name' => 'fantasy'],
    'g' => ['id' => 50, 'name' => 'football']
]

Und ich möchte es basierend auf dem ID-Feld in jedem Subarray in ein neues Array gruppieren.

array
(
    10 => array
          (
            e => array ( id = 10, name = bananas )
          )
    20 => array
          (
            a => array ( id = 20, name = chimpanzee )
            c => array ( id = 20, name = dynasty )
          )
    40 => array
          (
            b => array ( id = 40, name = meeting )
          )
    50 => array
          (
            d => array ( id = 50, name = chocolate )
            f => array ( id = 50, name = fantasy )
            g => array ( id = 50, name = football )
          )
)

Benutzeravatar von Tim Cooper
Tim Cooper

$arr = array();

foreach ($old_arr as $key => $item) {
   $arr[$item['id']][$key] = $item;
}

ksort($arr, SORT_NUMERIC);

  • @Herbert, ich vermute, das Schreiben an eine nicht vorhandene ID wirkt sich auf die Leistung aus? oder löst es PHP-Warnungen aus?

    – Anson Kao

    27. September 2011 um 20:10 Uhr

  • @SampleJACK: Mein Fehler. Auf den ersten Blick dachte ich, er würde überprüfen, ob eine ID in existiert $old_arr. Jetzt, wo ich es genauer untersuche, benutze array_key_exists fügt diesem Code nichts hinzu. Das Ergebnis ist ohne sie genau das gleiche. In Bezug auf die Leistung: Es ruft eine Funktion in einem Array innerhalb einer Schleife auf, die jeden Leistungseinbruch überwiegen muss, den Sie durch das Schreiben auf einen nicht vorhandenen Schlüssel erleiden würden, daher würde ich vorschlagen, das Ganze fallen zu lassen if() Block.

    – Herbert

    27. September 2011 um 20:30 Uhr


  • @Herbert: Ich hatte es hinzugefügt, da ich dachte, dass ein Fehler angezeigt wird, wenn der Schwellenwert für die Fehlerberichterstattung zu niedrig ist. Ich habe es getestet und scheint nicht zu meckern.

    – Tim Cooper

    27. September 2011 um 20:39 Uhr

  • @Tim: Ja, ich habe meine Fehlerberichterstattung aufgedreht, um sie anzuzeigen alles und Sie haben Recht – keine Beschwerden. Ich wollte nicht unterstellen, dass es sich in irgendeiner Weise um schlechten Code handelt. SampleJACK hat die Leistung erhöht, und nachdem man darüber nachgedacht hat, ist es sinnvoll, sie fallen zu lassen. Ehrlich gesagt dachte ich, es würde die IDs auf den inneren Arrays überprüfen. Das wird mich lehren, sorgfältiger zu lesen. :p Du bekommst immer noch meine +1 für guten Code.

    – Herbert

    27. September 2011 um 20:50 Uhr


  • Ich habe eine Antwort für die Nachwelt hinzugefügt, um zu verdeutlichen, worüber ich gesprochen habe.

    – Herbert

    27. September 2011 um 20:51 Uhr

foreach($array as $key => $value){
   $newarray[$value['id']][$key] = $value;
}

var_dump($newarray);

Stück Kuchen 😉

  • Wahrscheinlich ist es genauso einfach zu erklären, wie Ihr Code funktioniert und warum Sie der Meinung sind, dass dies die beste Technik ist.

    – mickmackusa

    17. Juni 2020 um 8:14 Uhr

  • Aber wirklich, es hat keinen neuen Wert, diese Antwort auf der Seite zu behalten. Diese Nur-Code-Antwort (ein exaktes Duplikat von Tims Technik) wurde 10 Minuten nach dem Posten von Tim gepostet.

    – mickmackusa

    17. Juni 2020 um 23:25 Uhr

Der folgende Code passt den Code von @Tim Cooper zur Minderung an Undefined index: id Fehler für den Fall, dass eines der inneren Arrays keine enthält Ausweis:

$arr = array();

foreach($old_arr as $key => $item)
{
    if(array_key_exists('id', $item))
        $arr[$item['id']][$key] = $item;
}

ksort($arr, SORT_NUMERIC);

Es werden jedoch innere Arrays ohne ID gelöscht.

Z.B

$old_arr = array(
    'a' => array ( 'id' => 20, 'name' => 'chimpanzee' ),
    'b' => array ( 'id' => 40, 'name' => 'meeting' ),
    'c' => array ( 'id' => 20, 'name' => 'dynasty' ),
    'd' => array ( 'id' => 50, 'name' => 'chocolate' ),
    'e' => array ( 'id' => 10, 'name' => 'bananas' ),
    'f' => array ( 'id' => 50, 'name' => 'fantasy' ),
    'g' => array ( 'id' => 50, 'name' => 'football' ),
    'h' => array ( 'name' => 'bob' )
);

wird das ‘h’-Array vollständig löschen.

  • Dies ist ein “erfundenes Problem” – nicht in der Frage des OP enthalten. Wahrscheinlich besser, eine andere Frage zu finden, die dieses Problem aufwirft, und sie dort zu posten.

    – mickmackusa

    17. Juni 2020 um 23:13 Uhr


Benutzeravatar von Piotr Olaszewski
Piotr Olaszewski

Sie können auch verwenden Arrays::groupBy() aus Ouzo-Leckereien:

$groupBy = Arrays::groupBy($array, Functions::extract()->id);

print_r($groupBy);

Und Ergebnis:

Array
(
    [20] => Array
        (
            [0] => Array
                (
                    [id] => 20
                    [name] => chimpanzee
                )

            [1] => Array
                (
                    [id] => 20
                    [name] => dynasty
                )

        )

    [40] => Array
        (
            [0] => Array
                (
                    [id] => 40
                    [name] => meeting
                )

        )

    [50] => Array
        (
            [0] => Array
                (
                    [id] => 50
                    [name] => chocolate
                )

            [1] => Array
                (
                    [id] => 50
                    [name] => fantasy
                )

            [2] => Array
                (
                    [id] => 50
                    [name] => football
                )

        )

    [10] => Array
        (
            [0] => Array
                (
                    [id] => 10
                    [name] => bananas
                )

        )

)

Und hier sind die Dokumente für Arrays Und Funktionen.

Hier ist eine Funktion, die ein Array als erstes Argument und ein Kriterium (eine Zeichenfolge oder eine Callback-Funktion) als zweites Argument akzeptiert. Die Funktion gibt ein neues Array zurück, das das Array wie gewünscht gruppiert.

/**
 * Group items from an array together by some criteria or value.
 *
 * @param  $arr array The array to group items from
 * @param  $criteria string|callable The key to group by or a function the returns a key to group by.
 * @return array
 *
 */
function groupBy($arr, $criteria): array
{
    return array_reduce($arr, function($accumulator, $item) use ($criteria) {
        $key = (is_callable($criteria)) ? $criteria($item) : $item[$criteria];
        if (!array_key_exists($key, $accumulator)) {
            $accumulator[$key] = [];
        }

        array_push($accumulator[$key], $item);
        return $accumulator;
    }, []);
}

Hier ist das angegebene Array:

$arr = array(
    'a' => array ( 'id' => 20, 'name' => 'chimpanzee' ),
    'b' => array ( 'id' => 40, 'name' => 'meeting' ),
    'c' => array ( 'id' => 20, 'name' => 'dynasty' ),
    'd' => array ( 'id' => 50, 'name' => 'chocolate' ),
    'e' => array ( 'id' => 10, 'name' => 'bananas' ),
    'f' => array ( 'id' => 50, 'name' => 'fantasy' ),
    'g' => array ( 'id' => 50, 'name' => 'football' )
);

Und Beispiele, die die Funktion mit einer Zeichenfolge und einer Callback-Funktion verwenden:

$q = groupBy($arr, 'id');
print_r($q);

$r = groupBy($arr, function($item) {
    return $item['id'];
});
print_r($r);

Die Ergebnisse sind in beiden Beispielen gleich:

Array
(
    [20] => Array
        (
            [0] => Array
                (
                    [id] => 20
                    [name] => chimpanzee
                )

            [1] => Array
                (
                    [id] => 20
                    [name] => dynasty
                )

        )

    [40] => Array
        (
            [0] => Array
                (
                    [id] => 40
                    [name] => meeting
                )

        )

    [50] => Array
        (
            [0] => Array
                (
                    [id] => 50
                    [name] => chocolate
                )

            [1] => Array
                (
                    [id] => 50
                    [name] => fantasy
                )

            [2] => Array
                (
                    [id] => 50
                    [name] => football
                )

        )

    [10] => Array
        (
            [0] => Array
                (
                    [id] => 10
                    [name] => bananas
                )

        )

)

Das Übergeben des Rückrufs ist im obigen Beispiel übertrieben, aber die Verwendung des Rückrufs findet seine Verwendung, wenn Sie ein Array von Objekten, ein mehrdimensionales Array oder etwas Willkürliches übergeben, nach dem Sie gruppieren möchten.

Benutzeravatar von SaeedPooyanfar
Said Pooyanfar

Vielleicht ist es erwähnenswert, dass Sie auch PHP verwenden können array_reduce Funktion

$items = [
    ['id' => 20, 'name' => 'chimpanzee'],
    ['id' => 40, 'name' => 'meeting'],
    ['id' => 20, 'name' => 'dynasty'],
    ['id' => 50, 'name' => 'chocolate'],
    ['id' => 10, 'name' => 'bananas'],
    ['id' => 50, 'name' => 'fantasy'],
    ['id' => 50, 'name' => 'football'],
];

// Grouping
$groupedItems = array_reduce($items, function ($carry, $item) {
    $carry[$item['id']][] = $item;
    return $carry;
}, []);
// Sorting
ksort($groupedItems, SORT_NUMERIC);

print_r($groupedItems);

https://www.php.net/manual/en/function.array-reduce.php

Benutzeravatar von mickmackusa
mickmackusa

Aufgrund der Art und Weise, wie der Sortieralgorithmus von PHP mehrdimensionale Arrays behandelt – er sortiert nach Größe und vergleicht dann die Elemente einzeln, können Sie tatsächlich eine schlüsselerhaltende Sortierung für die Eingabe verwenden, BEVOR Sie sie umstrukturieren. Bei der funktionalen Programmierung bedeutet dies, dass Sie das Ergebnisarray nicht als Variable deklarieren müssen.

Code: (Demo)

asort($array);
var_export(
    array_reduce(
        array_keys($array),
        function($result, $k) use ($array) {
            $result[$array[$k]['id']][$k] = $array[$k];
            return $result;
        }
    )
);

Ich muss sagen, dass die funktionale Programmierung für diese Aufgabe nicht sehr attraktiv ist, da die Schlüssel der ersten Ebene erhalten bleiben müssen.

Obwohl array_walk() prägnanter ist, erfordert es immer noch, dass das Ergebnisarray als Referenzvariable an die Closure übergeben wird. (Demo)

asort($array);
$result = [];
array_walk(
    $array,
    function($row, $k) use (&$result) {
        $result[$row['id']][$k] = $row;
    }
);
var_export($result);

Ich würde wahrscheinlich eine klassische Schleife für diese Aufgabe empfehlen. Das Einzige, was die Schleife tun muss, ist, die Tasten der ersten und zweiten Ebene neu anzuordnen. (Demo)

asort($array);
$result = [];
foreach ($array as $k => $row) {
    $result[$row['id']][$k] = $row;
}
var_export($result);

Ehrlich gesagt erwarte ich das ksort() wird effizienter sein als Pre-Loop-Sortierung, aber ich wollte eine praktikable Alternative.

1445090cookie-checkGruppieren Sie Zeilen in einem assoziativen Array von assoziativen Arrays nach Spaltenwert und bewahren Sie die ursprünglichen Schlüssel der ersten Ebene

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

Privacy policy