web-dev-qa-db-fra.com

Trier un tableau par clés en fonction d'un autre tableau?

Est-il possible dans PHP de faire quelque chose comme ça? Comment feriez-vous pour écrire une fonction? Voici un exemple. L'ordre est la chose la plus importante.

$customer['address'] = '123 fake st';
$customer['name'] = 'Tim';
$customer['dob'] = '12/08/1986';
$customer['dontSortMe'] = 'this value doesnt need to be sorted';

Et j'aimerais faire quelque chose comme 

$properOrderedArray = sortArrayByArray($customer, array('name', 'dob', 'address'));

Parce que finalement, j'utilise un foreach () et ils ne sont pas dans le bon ordre (parce que j'ajoute les valeurs à une chaîne qui doit être dans le bon ordre et que je ne connais pas à l'avance toutes les clés valeurs).

J'ai parcouru les fonctions de tableau internes de PHP, mais il semble que vous ne pouvez trier que par ordre alphabétique ou numérique. 

121
alex

Utilisez simplement array_merge ou array_replace. Array_merge fonctionne en commençant par le tableau que vous donnez (dans le bon ordre) et en écrasant/ajoutant les clés avec les données de votre tableau actuel:

$customer['address'] = '123 fake st';
$customer['name'] = 'Tim';
$customer['dob'] = '12/08/1986';
$customer['dontSortMe'] = 'this value doesnt need to be sorted';

$properOrderedArray = array_merge(array_flip(array('name', 'dob', 'address')), $customer);
//Or:
$properOrderedArray = array_replace(array_flip(array('name', 'dob', 'address')), $customer);

//$properOrderedArray -> array('name' => 'Tim', 'address' => '123 fake st', 'dob' => '12/08/1986', 'dontSortMe' => 'this value doesnt need to be sorted')

ps - Je réponds à cette question obsolète, car je pense que toutes les boucles données dans les réponses précédentes sont excessives.

298
Darkwaltz4

Voilà:

function sortArrayByArray(array $array, array $orderArray) {
    $ordered = array();
    foreach ($orderArray as $key) {
        if (array_key_exists($key, $array)) {
            $ordered[$key] = $array[$key];
            unset($array[$key]);
        }
    }
    return $ordered + $array;
}
95
Eran Galperin

Une autre façon pour PHP> = 5.3.0:

$customer['address'] = '123 fake st';
$customer['name'] = 'Tim';
$customer['dob'] = '12/08/1986';
$customer['dontSortMe'] = 'this value doesnt need to be sorted';

$customerSorted = array_replace(array_flip(array('name', 'dob', 'address')), $customer);

Résultat:

Array (
  [name] => Tim
  [dob] => 12/08/1986
  [address] => 123 fake st
  [dontSortMe] => this value doesnt need to be sorted
)

Fonctionne bien avec une chaîne et des touches numériques.

34
ekuser

Que diriez-vous de cette solution

$order = array(1,5,2,4,3,6);

$array = array(
    1 => 'one',
    2 => 'two',
    3 => 'three',
    4 => 'four',
    5 => 'five',
    6 => 'six'
);

uksort($array, function($key1, $key2) use ($order) {
    return (array_search($key1, $order) > array_search($key2, $order));
});
30
Peter de Groot
function sortArrayByArray(array $toSort, array $sortByValuesAsKeys)
{
    $commonKeysInOrder = array_intersect_key(array_flip($sortByValuesAsKeys), $toSort);
    $commonKeysWithValue = array_intersect_key($toSort, $commonKeysInOrder);
    $sorted = array_merge($commonKeysInOrder, $commonKeysWithValue);
    return $sorted;
}
22
OIS

Prenez un tableau comme commande:

$order = array('north', 'east', 'south', 'west');

Vous pouvez trier un autre tableau en fonction de valeurs à l’aide de array_intersectDocs :

/* sort by value: */
$array = array('south', 'west', 'north');
$sorted = array_intersect($order, $array);
print_r($sorted);

Ou dans votre cas, pour trier les clés, utilisez array_intersect_keyDocs :

/* sort by key: */
$array = array_flip($array);
$sorted = array_intersect_key(array_flip($order), $array);
print_r($sorted);

Les deux fonctions conserveront l'ordre du premier paramètre et renverront uniquement les valeurs (ou clés) du second tableau.

Ainsi, pour ces deux cas standard, vous n'avez pas besoin d'écrire une fonction pour effectuer le tri/la réorganisation.

14
hakre

J'ai utilisé la solution de Darkwaltz4, mais j'ai utilisé array_fill_keys au lieu de array_flip, pour remplir avec NULL si une clé n'est pas définie dans $array.

$properOrderedArray = array_replace(array_fill_keys($keys, null), $array);
4
Baptiste Bernard

SI vous avez un tableau dans votre tableau, vous devrez adapter un peu la fonction de Eran ...

function sortArrayByArray($array,$orderArray) {
    $ordered = array();
    foreach($orderArray as $key => $value) {
        if(array_key_exists($key,$array)) {
                $ordered[$key] = $array[$key];
                unset($array[$key]);
        }
    }
    return $ordered + $array;
}
2
Boombastic

Sans magie ...

$array=array(28=>c,4=>b,5=>a);
$seq=array(5,4,28);    
SortByKeyList($array,$seq) result: array(5=>a,4=>b,28=>c);

function sortByKeyList($array,$seq){
    $ret=array();
    if(empty($array) || empty($seq)) return false;
    foreach($seq as $key){$ret[$key]=$dataset[$key];}
    return $ret;
}
2
Jenovai Matyas

Cette fonction retourne un tableau sous et trié basé sur le second paramètre $ keys

function array_sub_sort(array $values, array $keys){
    $keys = array_flip($keys);
    return array_merge(array_intersect_key($keys, $values), array_intersect_key($values, $keys));
}

Exemple:

$array_complete = [
    'a' => 1,
    'c' => 3,
    'd' => 4,
    'e' => 5,
    'b' => 2
];

$array_sub_sorted = array_sub_sort($array_complete, ['a', 'b', 'c']);//return ['a' => 1, 'b' => 2, 'c' => 3];
1
Doglas

PHP a des fonctions pour vous aider avec ceci:

$arrayToBeSorted = array('west', 'east', 'south', 'north');
$order = array('north', 'south', 'east', 'west');

// sort array
usort($arrayToBeSorted, function($a, $b) use ($order){
    // sort using the numeric index of the second array
    $valA = array_search($a, $order);
    $valB = array_search($b, $order);

    // move items that don't match to end
    if ($valA === false)
        return -1;
    if ($valB === false)
        return 0;

    if ($valA > $valB)
        return 1;
    if ($valA < $valB)
        return -1;
    return 0;
});

Usort fait tout le travail pour vous et array_search fournit les clés. array_search () renvoie false lorsqu'il ne trouve pas de correspondance. Les éléments qui ne figurent pas dans le tableau de tri se déplacent naturellement vers le bas.

Remarque: uasort () ordonnera le tableau sans affecter les relations clé => valeur.

0
danielcraigie
  • trier comme demandé
  • save for int-keys (en raison de array_replace)
  • ne retourne pas les clés n'existent pas dans inputArray
  • (facultatif) pas de clés de filtre existantes dans la liste de clés donnée

Code:

 /**
 * sort keys like in key list
 * filter: remove keys are not listed in keyList
 * ['c'=>'red', 'd'=>'2016-12-29'] = sortAndFilterKeys(['d'=>'2016-12-29', 'c'=>'red', 'a'=>3 ]], ['c', 'd', 'z']){
 *
 * @param array $inputArray
 * @param string[]|int[] $keyList
 * @param bool $removeUnknownKeys
 * @return array
 */
static public function sortAndFilterKeys($inputArray, $keyList, $removeUnknownKeys=true){
    $keysAsKeys = array_flip($keyList);
    $result = array_replace($keysAsKeys, $inputArray); // result = sorted keys + values from input + 
    $result = array_intersect_key($result, $inputArray); // remove keys are not existing in inputArray 
    if( $removeUnknownKeys ){
        $result = array_intersect_key($result, $keysAsKeys); // remove keys are not existing in keyList 
    }
    return $result;
}
0
Grain

Première suggestion 

function sortArrayByArray($array,$orderArray) {
    $ordered = array();
    foreach($orderArray as $key) {
        if(array_key_exists($key,$array)) {
            $ordered[$key] = $array[$key];
            unset($array[$key]);
        }
    }
    return $ordered + $array;
}

Deuxième suggestion

$properOrderedArray = array_merge(array_flip(array('name', 'dob', 'address')), $customer);

Je voulais souligner que ces deux suggestions sont géniales. Cependant, ce sont des pommes et des oranges. La différence? L'un est convivial non-associatif et l'autre est convivial. Si vous utilisez 2 tableaux totalement associatifs, la fusion/retournement de tableau fusionnera et remplacera l'autre tableau associatif. Dans mon cas, ce ne sont pas les résultats que je cherchais. J'ai utilisé un fichier settings.ini pour créer mon tableau d'ordre de tri. Le tableau de données que je triais n'a pas besoin d'être remplacé par mon homologue de tri associatif. Ainsi, la fusion de tableaux détruirait mon tableau de données. Les deux méthodes sont excellentes et doivent être archivées dans une boîte à outils de développement. En fonction de vos besoins, vous constaterez peut-être que vous avez réellement besoin des deux concepts dans vos archives.

0
user1653711

J'ai adopté la réponse de @ Darkwaltz4 pour sa brièveté et je voudrais partager comment j'ai adapté la solution aux situations où le tableau peut contenir différentes clés pour chaque itération, comme ceci:

Array[0] ...
['dob'] = '12/08/1986';
['some_key'] = 'some value';

Array[1] ...
['dob'] = '12/08/1986';

Array[2] ...
['dob'] = '12/08/1986';
['some_key'] = 'some other value';

et maintenu une "clé principale" comme ceci:

$master_key = array( 'dob' => ' ' ,  'some_key' => ' ' );

array_merge aurait exécuté la fusion dans l'itération Array [1] en fonction de $ master_key et aurait produit ['some_key'] = '', une valeur vide pour cette itération. Ainsi, array_intersect_key a été utilisé pour modifier $ master_key dans chaque itération de la manière suivante:

foreach ($customer as $customer) {
  $modified_key = array_intersect_key($master_key, $unordered_array);
  $properOrderedArray = array_merge($modified_key, $customer);
}
0
Pageii Studio