Wie gruppiere ich Subarrays nach einem Spaltenwert?


74

Ich habe das folgende Array

Array
(
    [0] => Array
        (
            [id] => 96
            [shipping_no] => 212755-1
            [part_no] => reterty
            [description] => tyrfyt
            [packaging_type] => PC
        )

    [1] => Array
        (
            [id] => 96
            [shipping_no] => 212755-1
            [part_no] => dftgtryh
            [description] => dfhgfyh
            [packaging_type] => PC
        )

    [2] => Array
        (
            [id] => 97
            [shipping_no] => 212755-2
            [part_no] => ZeoDark
            [description] => s%c%s%c%s
            [packaging_type] => PC
        )

)

Wie kann ich das Array gruppieren id? Gibt es dafür native PHP-Funktionen?

Während dieser Ansatz funktioniert, möchte ich dies mit a tun foreach, da ich mit den oben genannten doppelten Elementen erhalte, die ich vermeiden möchte .

Auf dem obigen Beispiel idhaben 2 Elemente, so dass es innerhalb der sein mussid


Möchten Sie auch Duplikate entfernen?
Baba

Die meisten Lösungen verwenden einen FOREACH.
Justin John

@JustinJohn Die meisten Lösungen verwenden ONE FOREACH für die Array-Erstellung. Das Endergebnis ist kein Array. Ich habe nach einer besseren Lösung gesucht.
Red

1
Sie meinen, das Endergebnis ist kein eindimensionales Array.
Justin John

Ich meine ... ich muss auf jedes erstellte Array zugreifen, um es in Werte von HTML-Elementen zu konvertieren.
Red

Antworten:


163

Es gibt keine native, verwenden Sie einfach eine Schleife.

$result = array();
foreach ($data as $element) {
    $result[$element['id']][] = $element;
}

2
Sie brauchen das nicht if- der wahre Teil funktioniert in beiden Fällen.
Nicholas Shanks

1
Ich brauche hier keine if-Bedingung. Dies funktioniert genauso wie $result[$id][] = $data. Versuch es.
Ejaz Karim

Woher kennt das die ähnlichen IDs?
FiberOptics

Toller Code, hatte ein ähnliches Problem. Aber
obendrein muss


36

Sie können Folgendes versuchen:

$group = array();

foreach ( $array as $value ) {
    $group[$value['id']][] = $value;
}

var_dump($group);

Ausgabe:

array
  96 => 
    array
      0 => 
        array
          'id' => int 96
          'shipping_no' => string '212755-1' (length=8)
          'part_no' => string 'reterty' (length=7)
          'description' => string 'tyrfyt' (length=6)
          'packaging_type' => string 'PC' (length=2)
      1 => 
        array
          'id' => int 96
          'shipping_no' => string '212755-1' (length=8)
          'part_no' => string 'dftgtryh' (length=8)
          'description' => string 'dfhgfyh' (length=7)
          'packaging_type' => string 'PC' (length=2)
  97 => 
    array
      0 => 
        array
          'id' => int 97
          'shipping_no' => string '212755-2' (length=8)
          'part_no' => string 'ZeoDark' (length=7)
          'description' => string 's%c%s%c%s' (length=9)
          'packaging_type' => string 'PC' (length=2)

27

In einem funktionaleren Programmierstil könnten Sie verwenden array_reduce

$groupedById = array_reduce($data, function (array $accumulator, array $element) {
  $accumulator[$element['id']][] = $element;

  return $accumulator;
}, []);

18

Ich habe das einfach zusammengeschmissen, inspiriert von .NET LINQ

<?php

// callable type hint may be "closure" type hint instead, depending on php version
function array_group_by(array $arr, callable $key_selector) {
  $result = array();
  foreach ($arr as $i) {
    $key = call_user_func($key_selector, $i);
    $result[$key][] = $i;
  }  
  return $result;
}

 $data = array(
        array(1, "Andy", "PHP"),
        array(1, "Andy", "C#"),
        array(2, "Josh", "C#"),
        array(2, "Josh", "ASP"),
        array(1, "Andy", "SQL"),
        array(3, "Steve", "SQL"),
    );

$grouped = array_group_by($data, function($i){  return $i[0]; });

var_dump($grouped);

?>

Und voila bekommst du

array(3) {
  [1]=>
  array(3) {
    [0]=>
    array(3) {
      [0]=>
      int(1)
      [1]=>
      string(4) "Andy"
      [2]=>
      string(3) "PHP"
    }
    [1]=>
    array(3) {
      [0]=>
      int(1)
      [1]=>
      string(4) "Andy"
      [2]=>
      string(2) "C#"
    }
    [2]=>
    array(3) {
      [0]=>
      int(1)
      [1]=>
      string(4) "Andy"
      [2]=>
      string(3) "SQL"
    }
  }
  [2]=>
  array(2) {
    [0]=>
    array(3) {
      [0]=>
      int(2)
      [1]=>
      string(4) "Josh"
      [2]=>
      string(2) "C#"
    }
    [1]=>
    array(3) {
      [0]=>
      int(2)
      [1]=>
      string(4) "Josh"
      [2]=>
      string(3) "ASP"
    }
  }
  [3]=>
  array(1) {
    [0]=>
    array(3) {
      [0]=>
      int(3)
      [1]=>
      string(5) "Steve"
      [2]=>
      string(3) "SQL"
    }
  }
}

8

Verwenden Sie den Spaltenwert, nach dem Sie gruppieren möchten, und speichern Sie ihn im Cache. Verschieben Sie dann die verbleibenden Daten als neues Unterarray der Gruppe, die Sie im Ergebnis erstellt haben.

function array_group(array $data, $by_column)
{
    $result = [];
    foreach ($data as $item) {
        $column = $item[$by_column];
        unset($item[$by_column]);
        $result[$column][] = $item;
    }
    return $result;
}

3

Diese Funktion array_group_by erreicht das, wonach Sie suchen:

$grouped = array_group_by($arr, 'id');

Es werden sogar mehrstufige Gruppierungen unterstützt:

$grouped = array_group_by($arr, 'id', 'part_no');

Warnung: Diese Methode array_group_byführt die Variable $keyals Methodenparameter ein und wird imforeach
DannyFeliz

3

$ arr = Data Araay;

$ fldName = Gruppieren nach Spaltenname;

function array_group_by( $arr, $fldName) {
    $groups = array();
    foreach ($arr as $rec) {
        $groups[$rec[$fldName]] = $rec;
    }
    return $groups;
}

function object_group_by( $obj, $fldName) {
    $groups = array();
    foreach ($obj as $rec) {
        $groups[$rec->$fldName] = $rec;
    }
    return $groups;
}

2
$arr = array();

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

ksort($arr, SORT_NUMERIC);

Bitte, __ Zuerst muss ich das Array manipulieren? und dann wieder foreach für den eigentlichen Zweck?
Red

2
for($i = 0 ; $i < count($arr)  ; $i++ )
{
    $tmpArr[$arr[$i]['id']] = $arr[$i]['id'];
}
$vmpArr = array_keys($tmpArr);
print_r($vmpArr);

Diese Antwort ist sehr falsch - sie gibt nur die Schlüssel zurück und tötet Duplikate. Es wird auch die schlechte Praxis angewendet, count()jede Iteration aufzurufen . Nur-Code-Antworten sind bei SO von geringem Wert. Ich könnte Upvoters nie verstehen.
Mickmackusa

2

Erweitern der Antwort von @ baba, die mir gefällt, aber eine komplexere dreistufige tiefe mehrdimensionale (Array (Array (Array))) erzeugt:

$group = array();
 foreach ( $array as $value ) {
   $group[$value['id']][] = $value; 
 }

// output only data from id 96
foreach ($group as $key=>$value) { //outer loop
 foreach ($value as $k=>$v){ //inner loop
  if($key==96){ //if outer loop is equal to 96 (could be variable)
   for ($i=0;$i<count($k);$i++){ //iterate over the inner loop
        printf($key.' has a part no. of '.$v['part_no'].' and shipping no. of '.$v['shipping_no'].'<br>');
   }
 }
}
 }

Wird ausgegeben:

96 hat eine Teile-Nr. Reterty und Versandnummer von 212755-1

96 hat eine Teile-Nr. von dftgtryh und Versandnummer von 212755-1


2

Es ist trivial, mit LINQ zu tun, das in PHP in mehreren Bibliotheken implementiert ist, einschließlich YaLinqo *. Es ermöglicht das Ausführen von SQL-ähnlichen Abfragen für Arrays und Objekte. Die groubByFunktion wurde speziell für die Gruppierung entwickelt. Sie müssen lediglich das Feld angeben, nach dem Sie gruppieren möchten:

$grouped_array = from($array)->groupBy('$v["id"]')->toArray();

Wo '$v["id"]'ist eine Abkürzung, function ($v) { return $v["id"]; }die diese Bibliothek unterstützt?

Das Ergebnis ist genau wie in der akzeptierten Antwort, nur mit weniger Code.

* von mir entwickelt


Können Sie mir einen Hinweis geben, wie man nach mehreren Feldern gruppiert? In meinem Anwendungsfall habe ich ein Objekt mit einem Datumsfeld und muss es nach Jahr, Monat und Datum gruppieren. So etwas wie {2016 => {09 => {15 => $ object}}}
fnagel

1
@fnagel Verschachtelte Gruppierung ist etwas kompliziert. Siehe das Support-Problem zu verschachtelten groupBy . Es enthält eine group_by_multipleHilfsfunktion sowie eine ausführliche Erklärung der Funktionsweise verschachtelter Gruppierungen. Mit dieser Funktion sieht Ihre Abfrage so aus group_by_multiple($objects, [ '$v->date->format("Y")', '$v->date->format("n")', '$v->date->format("j")' ]).
Athari

2

1. GROUP BYein Schlüssel

Diese Funktion funktioniert wie GROUP BYfür ein Array, jedoch mit einer wichtigen Einschränkung: Es ist nur eine Gruppierung "column" ( $identifier) möglich.

function arrayUniqueByIdentifier(array $array, string $identifier)
{
    $ids = array_column($array, $identifier);
    $ids = array_unique($ids);
    $array = array_filter($array,
        function ($key, $value) use($ids) {
            return in_array($value, array_keys($ids));
        }, ARRAY_FILTER_USE_BOTH);
    return $array;
}

2. Erkennen der eindeutigen Zeilen für eine Tabelle (zweidimensionales Array)

Diese Funktion dient zum Filtern von "Zeilen". Wenn wir sagen, ein zweidimensionales Array ist eine Tabelle, dann ist jedes Element eine Zeile. Mit dieser Funktion können wir also die duplizierten Zeilen entfernen. Zwei Zeilen (Elemente der ersten Dimension) sind gleich, wenn alle Spalten (Elemente der zweiten Dimension) gleich sind. Für den Vergleich von "Spalten" -Werten gilt: Wenn ein Wert von einem einfachen Typ ist , wird der Wert selbst beim Vergleichen verwendet; sonst seine Art ( array, object, resource, unknown type) verwendet.

Die Strategie ist einfach: Erstellen Sie aus dem ursprünglichen Array ein flaches Array, wobei die Elemente imploded "Spalten" des ursprünglichen Arrays sind. dann bewerben array_unique(...)Sie sich darauf; und als letztes verwenden Sie die erkannten IDs zum Filtern des ursprünglichen Arrays.

function arrayUniqueByRow(array $table = [], string $implodeSeparator)
{
    $elementStrings = [];
    foreach ($table as $row) {
        // To avoid notices like "Array to string conversion".
        $elementPreparedForImplode = array_map(
            function ($field) {
                $valueType = gettype($field);
                $simpleTypes = ['boolean', 'integer', 'double', 'float', 'string', 'NULL'];
                $field = in_array($valueType, $simpleTypes) ? $field : $valueType;
                return $field;
            }, $row
        );
        $elementStrings[] = implode($implodeSeparator, $elementPreparedForImplode);
    }
    $elementStringsUnique = array_unique($elementStrings);
    $table = array_intersect_key($table, $elementStringsUnique);
    return $table;
}

Es ist auch möglich, den Vergleich zu verbessern und die Klasse des "Spalten" -Werts zu erkennen, wenn es sich um einen Typ handelt object.

Das $implodeSeparatorsollte mehr oder weniger komplex sein, zB spl_object_hash($this).


3. Erkennen der Zeilen mit eindeutigen Bezeichnerspalten für eine Tabelle (zweidimensionales Array)

Diese Lösung basiert auf der zweiten. Jetzt muss die gesamte "Zeile" nicht eindeutig sein. Zwei "Zeilen" (Elemente der ersten Dimension) sind jetzt gleich, wenn alle relevanten "Felder" (Elemente der zweiten Dimension) der einen "Zeile" gleich den entsprechenden "Feldern" (Elemente mit demselben Schlüssel) sind.

Die "relevanten" "Felder" sind die "Felder" (Elemente der zweiten Dimension), die einen Schlüssel haben, der einem der Elemente der übergebenen "Bezeichner" entspricht.

function arrayUniqueByMultipleIdentifiers(array $table, array $identifiers, string $implodeSeparator = null)
{
    $arrayForMakingUniqueByRow = $removeArrayColumns($table, $identifiers, true);
    $arrayUniqueByRow = $arrayUniqueByRow($arrayForMakingUniqueByRow, $implodeSeparator);
    $arrayUniqueByMultipleIdentifiers = array_intersect_key($table, $arrayUniqueByRow);
    return $arrayUniqueByMultipleIdentifiers;
}

function removeArrayColumns(array $table, array $columnNames, bool $isWhitelist = false)
{
    foreach ($table as $rowKey => $row) {
        if (is_array($row)) {
            if ($isWhitelist) {
                foreach ($row as $fieldName => $fieldValue) {
                    if (!in_array($fieldName, $columnNames)) {
                        unset($table[$rowKey][$fieldName]);
                    }
                }
            } else {
                foreach ($row as $fieldName => $fieldValue) {
                    if (in_array($fieldName, $columnNames)) {
                        unset($table[$rowKey][$fieldName]);
                    }
                }
            }
        }
    }
    return $table;
}

1

Dies sollte ein assoziatives Array Ejm Group By Country gruppieren

function getGroupedArray($array, $keyFieldsToGroup) {   
    $newArray = array();

    foreach ($array as $record) 
        $newArray = getRecursiveArray($record, $keyFieldsToGroup, $newArray);

    return $newArray;
}
function getRecursiveArray($itemArray, $keys, $newArray) {
    if (count($keys) > 1) 
        $newArray[$itemArray[$keys[0]]] = getRecursiveArray($itemArray,    array_splice($keys, 1), $newArray[$itemArray[$keys[0]]]);
    else
        $newArray[$itemArray[$keys[0]]][] = $itemArray;

    return $newArray;
}

$countries = array(array('Country'=>'USA', 'State'=>'California'),
                   array('Country'=>'USA', 'State'=>'Alabama'),
                   array('Country'=>'BRA', 'State'=>'Sao Paulo'));

$grouped = getGroupedArray($countries, array('Country'));


1
function array_group_by($arr, array $keys) {

if (!is_array($arr)) {
    trigger_error('array_group_by(): The first argument should be an array', E_USER_ERROR);
}
if (count($keys)==0) {
    trigger_error('array_group_by(): The Second argument Array can not be empty', E_USER_ERROR);
}

// Load the new array, splitting by the target key
$grouped = [];
foreach ($arr as $value) {
    $grouped[$value[$keys[0]]][] = $value;
}

// Recursively build a nested grouping if more parameters are supplied
// Each grouped array value is grouped according to the next sequential key
if (count($keys) > 1) {
        foreach ($grouped as $key => $value) {
       $parms = array_merge([$value], [array_slice($keys, 1,count($keys))]);
       $grouped[$key] = call_user_func_array('array_group_by', $parms);

    }
}
return $grouped;

}}


1
function groupeByPHP($array,$indexUnique,$assoGroup,$keepInOne){
$retour = array();
$id = $array[0][$indexUnique];
foreach ($keepInOne as $keep){
    $retour[$id][$keep] = $array[0][$keep];
}
foreach ($assoGroup as $cle=>$arrayKey){
    $arrayGrouped = array();
        foreach ($array as $data){
            if($data[$indexUnique] != $id){
                $id = $data[$indexUnique];
                foreach ($keepInOne as $keep){
                    $retour[$id][$keep] = $data[$keep];
                }
            }
            foreach ($arrayKey as $val){
                $arrayGrouped[$val] = $data[$val];
            }
            $retour[$id][$cle][] = $arrayGrouped;
            $retour[$id][$cle] = array_unique($retour[$id][$cle],SORT_REGULAR);
        }
}
return  $retour;
}

Probieren Sie diese Funktion aus

groupeByPHP($yourArray,'id',array('desc'=>array('part_no','packaging_type')),array('id','shipping_no')) 

1

Rekursive Funktion, die das zweidimensionale Array vom ersten bis zum letzten Schlüssel gruppiert

Eingang:

$arr = array(
    '0' => array(
        'key0' => 'value0',
        'key1' => 'value1',
        'key2' => 'value02',
    ),
    '2' => array(
        'key0' => 'value0',
        'key1' => 'value1',
        'key2' => 'value12',
    ),
    '3' => array(
        'key0' => 'value0',
        'key1' => 'value3',
        'key2' => 'value22',
    ),
);
$keys = array('key0', 'key1', 'key2');

Ausgabe:

$arr = array(
    'value0' => array(
        'value1 => array(
            'value02' => null,
            'value12' => null,
        ),
        'value3' => 'value22',
    ),
);

Code:

function array_group_by_keys(&$arr, $keys) {

    if (count($arr) < 2){
        $arr = array_shift($arr[0]);
        return;
    }

    foreach ($arr as $k => $item) {
        $fvalue = array_shift($item);
        $arr[$fvalue][] = $item;
        unset($arr[$k]);
    }

    array_shift($keys);
    foreach ($arr as &$sub_arr) {
        array_group_by_keys($sub_arr, $keys);
    }
}

-3

Ich denke, dass dies in PHP 5.5+ besser funktioniert

$IdVar = array_column($data, 'id');

Was funktioniert? Was meinst du auch? Wie beantwortet es die Frage?
Dharman

Dadurch wird nur der Spaltenwert aus dem Array extrahiert und in das Array eingefügt. In diesem Fall wäre das Ergebnis['96','97']
user1718607
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.