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 puis-je regrouper le tableau par id? Y a-t-il des fonctions PHP natives disponibles pour le faire?

Si je foreach ce qui précède alors je vais obtenir un double, Comment puis-je éviter cela?

Sur l'exemple ci-dessus id ont 2 éléments, donc son besoin d'être à l'intérieur du id.

EDIT: TOUT FONCTIONNE BIEN: MAIS EST - IL POSSIBLE D'OBTENIR LA MÊME CHOSE AVEC UN FOREACH ?

39
demandé sur msanford 2012-10-03 14:14:11

16 réponses

Il n'est pas natif, il suffit d'utiliser une boucle.

$result = array();
foreach ($data as $element) {
    $result[$element['id']][] = $element;
}
90
répondu xdazz 2018-01-05 08:59:59

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)
26
répondu Baba 2014-05-19 09:59:14

Je viens de jeter 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"
    }
  }
}
15
répondu AndyClaw 2014-05-28 18:18:25

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

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

  return $accumulator;
}, []);
4
répondu atomrc 2018-01-05 08:55:35

J'avais aussi besoin d'une telle fonction. J'ai créé celui-ci, vous passez quelle colonne vous voulez regrouper 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;
}
3
répondu Nurlan Alekberov 2016-08-29 13:58:53
for($i = 0 ; $i < count($arr)  ; $i++ )
{
    $tmpArr[$arr[$i]['id']] = $arr[$i]['id'];
}
$vmpArr = array_keys($tmpArr);
print_r($vmpArr);
2
répondu Amrish Prajapati 2012-10-03 10:23:07

Cette fonction array_group_by réalise ce que vous recherchez:

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

Il prend même en charge les regroupements à plusieurs niveaux:

$grouped = array_group_by($arr, 'id', 'part_no');
2
répondu Mark W 2015-08-30 06:15:22

Expansion sur la réponse de @baba, que j'aime, mais crée un multi-dimensionnel profond à trois niveaux plus complexe (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>');
   }
 }
}
 }

Affichera:

96 a un numéro de pièce. de reterty 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

1
répondu rwhite35 2012-10-03 12:13:49

C'est trivial à voir avec LINQ, qui est implémenté en 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 conçue spécifiquement pour le regroupement, il vous suffit de spécifier le champ que vous souhaitez regrouper par:

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

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

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

* développé par moi

1
répondu Athari 2015-06-04 15:58:12

1. GROUP BY clé

Cette fonction fonctionne comme GROUP BY pour le tableau, mais avec une restriction importante: un Seul groupement "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 pour 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. Ainsi, nous pouvons supprimer les lignes dupliquées avec cette fonction. Deux rangées (éléments du premier dimension) sont égaux, si toutes leurs colonnes (éléments de la deuxième dimension) sont égales. À la comparaison des valeurs" colonne " s'applique: si une valeur est d'un type simple , 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: faire du tableau d'origine un tableau peu profond, où les éléments sont implode d "colonnes" du tableau d'origine; puis appliquer array_unique(...) dessus; et comme dernière utilisation des ID détectés pour le filtrage du tableau original.

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 à deux dimensions)

Cette solution repose sur la 2ème. Maintenant la complète "ligne" n'a pas besoin d'être unique. Deux "lignes" (éléments de la première dimension) sont égal maintenant, si tous les "champs" pertinents (éléments de la deuxième dimension) d'une "ligne" sont égaux aux "champs" correspondants (éléments avec la même clé).

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

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
répondu automatix 2016-05-24 11:10:41
$arr = array();

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

ksort($arr, SORT_NUMERIC);
0
répondu Sebass van Boxel 2012-10-03 10:16:50

Cela devrait regrouper un tableau associatif Groupe Ejm Par Pays

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'));
0
répondu Cesar Nieto 2015-09-08 18:11:38

Vérifier indexé la fonction de Nspl:

use function \nspl\a\indexed;
$grouped = indexed($data, 'id');
0
répondu Ihor Burlachenko 2016-03-04 18:20:48
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;

}

0
répondu mohamed zaki 2016-06-01 04:03:48

$arr = Données Araay;

$ fldName = groupe par nom de 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;
}
0
répondu Mahidul Islam 2018-08-02 05:29:46
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')) 
-1
répondu abdallah ismail 2018-02-01 16:09:12