105 votes

Comment grouper des sous-matrices par la valeur d'une colonne ?

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 grouper le tableau par id ? Y a-t-il des fonctions natives de php disponibles pour faire cela ?

Bien que cette approche fonctionne, je veux faire cela en utilisant une foreach En effet, avec ce qui précède, j'obtiendrai des éléments en double, ce que j'essaie d'éviter ?

Dans l'exemple ci-dessus id a deux éléments, il doit donc se trouver à l'intérieur de l'élément id

2voto

Athari Points 7821

Il est facile de le faire avec LINQ, qui est implémenté en PHP dans plusieurs bibliothèques, dont les suivantes YaLinqo *. Il permet d'effectuer des requêtes de type SQL sur des tableaux et des objets. Le site groubBy est conçue spécifiquement pour le regroupement, il vous suffit de spécifier le champ par lequel vous voulez regrouper :

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

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

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

* développé par moi

2voto

automatix Points 923

1. GROUP BY une clé

Cette fonction fonctionne comme GROUP BY pour le tableau, mais avec une limitation importante : Une seule "colonne" de regroupement ( $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étecter les lignes uniques d'un tableau (tableau bidimensionnel)

Cette fonction permet de filtrer les "rangées". Si nous disons qu'un tableau à deux dimensions est un tableau, alors chaque élément est une ligne. Cette fonction permet donc d'éliminer les lignes dupliquées. 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 "colonnes" s'applique : Si une valeur est d'un simple type la valeur elle-même sera utilisée pour la comparaison ; sinon, son type ( array , object , resource , unknown type ) seront utilisés.

La stratégie est simple : Créer à partir du tableau original un tableau peu profond, dont les éléments sont implode d "colonnes" du tableau original ; puis appliquer array_unique(...) et enfin, utiliser les identifiants détectés pour filtrer le 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 .

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


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

Cette solution repose sur la deuxième solution. Maintenant, la "rangée" complète n'a pas besoin d'être unique. Deux "rangées" (éléments de la première dimension) sont égales maintenant, si tous les éléments de la première dimension sont uniques. pertinent Les "champs" (éléments de la deuxième dimension) d'une "ligne" sont égaux aux "champs" correspondants (éléments ayant la même clé).

Les "champs" "pertinents" sont les "champs" (éléments de la deuxième dimension) dont la clé est égale à l'un des éléments des "identifiants" 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;
}

1voto

Cesar Nieto Points 11

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

1voto

Ihor Burlachenko Points 2037

Vérifiez indexé de la fonction Nspl :

use function \nspl\a\indexed;
$grouped = indexed($data, 'id');

1voto

mohamed zaki Points 11
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;

}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X