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

rot
quelle
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;
}
xdazz
quelle
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)
Baba
quelle
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;
}, []);
atomrc
quelle
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"
    }
  }
}
AndyClaw
quelle
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;
}
mickmackusa
quelle
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');
Jake Z.
quelle
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;
}
Mahidul Islam
quelle
2
$arr = array();

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

ksort($arr, SORT_NUMERIC);
Sebass van Boxel
quelle
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);
Amrish Prajapati
quelle
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

weiß
quelle
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

Athari
quelle
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;
}
automatix
quelle
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'));
Cesar Nieto
quelle
1

Überprüfen Sie die indizierte Funktion von Nspl :

use function \nspl\a\indexed;
$grouped = indexed($data, 'id');
Ihor Burlachenko
quelle
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;

}}

mohamed zaki
quelle
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')) 
ZeroCool
quelle
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);
    }
}
alsator
quelle
-3

Ich denke, dass dies in PHP 5.5+ besser funktioniert

$IdVar = array_column($data, 'id');
KR Vineeth
quelle
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