web-dev-qa-db-fra.com

groupe de tableaux php

J'ai le tableau suivant 

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
        )

)

Comment regrouper le tableau par id? Existe-t-il des fonctions php natives disponibles?

Si je foreach ce qui précède, j'en obtiendrai un en double, comment puis-je éviter cela?

Dans l'exemple ci-dessus, id a 2 éléments, il est donc nécessaire qu'il soit dans la id.

EDIT: TOUT MARCHE FIN: MAIS IS Y AT-IL UN MOYEN DE RÉALISER LA MÊME AVEC UNE PRÉAVANCE?

46
Red

Il n'y en a pas, utilisez simplement une boucle.

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

Vous pouvez essayer ce qui suit:

$group = array();

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

var_dump($group);

Sortie:

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)
29
Baba

Je viens de lancer cela ensemble, inspiré par .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);

?>

Et voila vous obtenez

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"
    }
  }
}
16
AndyClaw

Dans un style de programmation plus fonctionnel, vous pourriez utiliser array_reduce

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

  return $accumulator;
}, []);
10
atomrc

J'avais besoin d'une telle fonction aussi. J'ai créé celui-ci, vous transmettez quelle colonne vous souhaitez grouper par:

function array_group(array $data, $by_column)
{
    $result = [];

    foreach ($data as $item) {
        $column = $item[$by_column];
        unset($item[$by_column]);
        if (isset($result[$column])) {
            $result[$column][] = $item;
        } else {
            $result[$column] = array($item);
        }
    }

    return $result;
}
4
Nurlan Alekberov

Cette fonction array_group_by réalise ce que vous recherchez:

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

Il supporte même les groupements multi-niveaux:

$grouped = array_group_by($arr, 'id', 'part_no');
3
Jake Z
for($i = 0 ; $i < count($arr)  ; $i++ )
{
    $tmpArr[$arr[$i]['id']] = $arr[$i]['id'];
}
$vmpArr = array_keys($tmpArr);
print_r($vmpArr);
3
Amrish Prajapati

1. GROUP BY une touche

Cette fonction fonctionne comme GROUP BY pour tableau, mais avec une limitation importante: un seul groupe "colonne" ($identifier) est possible.

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. Détection des lignes uniques d'une table (tableau bidimensionnel)

Cette fonction sert à filtrer les "lignes". Si nous disons, un tableau bidimensionnel est une table, alors chaque élément est une ligne. Nous pouvons donc supprimer les lignes dupliquées avec cette fonction. Deux lignes (éléments de la première dimension) sont égales, si toutes leurs colonnes (éléments de la deuxième dimension) sont égales. La comparaison des valeurs "colonne" s'applique: Si une valeur est simple type , la valeur elle-même sera utilisée lors de la comparaison; sinon, son type (array, object, resource, unknown type) sera utilisé.

La stratégie est simple: créez à partir du tableau d'origine un tableau peu profond, où les éléments sont imploded "colonnes" du tableau d'origine; puis appliquez array_unique(...) dessus; et, en dernier lieu, utilisez les identifiants détectés pour filtrer le tableau d'origine.

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;
}

Il est également possible d'améliorer la comparaison en détectant la classe de la valeur "colonne", si son type est object.

Le $implodeSeparator devrait être plus ou moins complexe, z.B. spl_object_hash($this).


3. Détection des lignes avec des colonnes d'identifiant unique pour une table (tableau bidimensionnel)

Cette solution s'appuie sur la 2ème. Maintenant, la "ligne" complète n'a pas besoin d'être unique. Deux "lignes" (éléments de la première dimension) sont désormais égales, si tous les {pertinentsavec la même clé).

Les "champs" "pertinents" sont les "champs" (éléments de la deuxième dimension), qui ont une clé, qui sont égaux à l'un des éléments des "identificateurs" transmis.

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;
}
3
automatix

Il est trivial de le faire avec LINQ, qui est implémenté dans PHP dans plusieurs bibliothèques, y compris YaLinqo *. Il permet d'effectuer des requêtes de type SQL sur des tableaux et des objets. La fonction groubBy est spécialement conçue pour le regroupement. Il vous suffit de spécifier le champ que vous souhaitez grouper:

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

'$v["id"]' est un raccourci pour function ($v) { return $v["id"]; } pris en charge par cette bibliothèque.

Le résultat sera exactement comme dans la réponse acceptée, avec moins de code.

* développé par moi

2
Athari

Développer la réponse de @ baba, ce que j'aime bien, mais crée un multi-dimensionnel plus complexe à trois niveaux (array (array (array)))):

$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>');
   }
 }
}
 }

Est-ce que la sortie:

96 a un numéro de pièce. de retour et numéro d'expédition de 212755-1

96 a un numéro de pièce. de dftgtryh et numéro d'expédition de 212755-1

2
rwhite35

Cela devrait regrouper un tableau associatif Ejm Group By Country

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
Cesar Nieto

Vérifiez indexé fonction de Nspl :

use function \nspl\a\indexed;
$grouped = indexed($data, 'id');
1
Ihor Burlachenko
$arr = array();

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

ksort($arr, SORT_NUMERIC);
1
Sebass van Boxel

$ arr = tableau de données;

$ fileName = Nom du groupe par colonne;

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;
}
1
Mahidul Islam
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
mohamed zaki

Fonction récursive regroupant un tableau à 2 dimensions par touches du premier au dernier

Contribution:

$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');

Sortie:

$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);
    }
}
0
alsator
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;
}

Essayez cette fonction 

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