tags:

views:

381

answers:

9

Example:

$arr = array('apple'=>'sweet','grapefruit'=>'bitter','pear'=>'tasty','banana'=>'yellow');

I want to switch the positions of grapefruit and pear, so the array will become

'apple'=>'sweet','pear'=>'tasty','grapefruit'=>'bitter','banana'=>'yellow')

I know the keys and values of the elements I want to switch, is there an easy way to do this? Or will it require a loop + creating a new array?

Thanks

+1  A: 

There is not easy way, just a loop or a new array definition.

And I got a question for you: is this really useful? What convenience do you have in switching them?

Lex
It's for using with Drupal form API, the order of the array determines the order each element (field) is printed. However, I can also use the '#weight' property to alter the order which it seems would be easier. It just means iterating over each field to set a new weight.
I agree with Lex. PHP does not provide a native function to swap array items. You can probably write your own with a combination of the rest of the array functions and lots of patience but, honestly, rewriting the full array with a foreach loop is by far the easiest method. A custom swap function is not worth the effort unless you handle very large arrays and, in such case, you should probably redesign that part of the code logic.
Álvaro G. Vicario
A: 

Classical associative array doesn't define or guarantee sequence of elements in any way. There is plain array/vector for that. If you use associative array you are assumed to need random access but not sequential. For me you are using assoc array for task it is not made for.

Andrey
If that was true, it'd make asort() any other builtin functions completely useless...
Álvaro G. Vicario
if you see i wrote "Classical associative array", not "php associative array". Function asort is specific to php implementation. again what i said is correct, one should assoc arrays for random access. if people would care look a bit wider than just PHP...
Andrey
What's the problem of using PHP implementations when coding in PHP? Do you write language agnostic PHP code? What for? So you can run your PHP with a Perl interpreter? :-?
Álvaro G. Vicario
key part was that assoc array was made for "random access". if you try to use it for sequential access most probably you designed your code incorrectly.
Andrey
-1 because the order is a well defined and supported feature of php.
chris
the only supported thing is that this order is same if array is not modified. i downloaded php sources and saw that assoc arrray is implemented as a hash table + linked list for iteration. what you call by "order" is position in that linked list. you can edit this list in any way, just by adding or removing elements. no one can define that this list will be populated the same way in every php version.
Andrey
the only reason this list is persisted is iteration of all values, because it is hard to fetch them from hash table itself. other use of it are architecturally incorrect and can appear due to lack of basic data structure principles.
Andrey
the php array is an _ordered_ map. It is a feature. It is predictable. It is advertised as being so. Numerous occurrences of native functions and documentation rely on this feature.
chris
where did you get that it is ordered? i took **sources** of file php.exe and saw implementation of it. Associative array in PHP is Hashmap for O(1) access and linked list for traversal.
Andrey
First sentence http://www.php.net/manual/en/language.types.array.php
chris
A: 
$temp = $array['pear'];
$array['pear'] = $array['grapefruit'];
$array['grapefruit'] = $temp;
Sparky
Not to nit-pick, but I had to change the order it was displayed, it was bothering me.
Anthony Forloney
This code swaps values, not elements
Álvaro G. Vicario
A: 

Arrays in php are ordered maps.

$arr = array('apple'=>'sweet','grapefruit'=>'bitter','
pear'=>'tasty','banana'=>'yellow');

doesn't mean that that the first element is 'apple'=>'sweet' and the last - 'banana'=>'yellow' just because you put 'apple' first and 'banana' last. Actually, 'apple'=>'sweet' will be the first and 'banana'=>'yellow' will be the second because of alphabetical ascending sort order.

a1ex07
This would only be true after a `ksort()`. Indexed arrays maintain their ordering (eg. the order in which the array elements are initialized)
keithjgrant
-1 by default, elements are implicitly ordered by the time that a key was initialized.
chris
A: 

yeah I agree with Lex, if you are using an associative array to hold data, why not using your logic handle how they are accessed instead of depending on how they are arranged in the array.

If you really wanted to make sure they were in a correct order, trying creating fruit objects and then put them in a normal array.

Bryan Clark
+1  A: 

There is no easy way to do this. This sounds like a slight design-logic error on your part which has lead you to try to do this when there is a better way to do whatever it is you are wanting to do. Can you tell us why you want to do this?

You say that I know the keys and values of the elements I want to switch which makes me think that what you really want is a sorting function since you can easily access the proper elements anytime you want as they are.

$value = $array[$key];

If that is the case then I would use sort(), ksort() or one of the many other sorting functions to get the array how you want. You can even use usort() to Sort an array by values using a user-defined comparison function.

Other than that you can use array_replace() if you ever need to swap values or keys.

Xeoncross
+1  A: 

if the array comes from the db, add a sort_order field so you can always be sure in what order the elements are in the array.

dazz
+1  A: 

This may or may not be an option depending on your particular use-case, but if you initialize your array with null values with the appropriate keys before populating it with data, you can set the values in any order and the original key-order will be maintained. So instead of swapping elements, you can prevent the need to swap them entirely:

$arr = array('apple' => null,
             'pear' => null,
             'grapefruit' => null,
             'banana' => null);

...

$arr['apple'] = 'sweet';
$arr['grapefruit'] = 'bitter'; // set grapefruit before setting pear
$arr['pear'] = 'tasty';
$arr['banana'] = 'yellow';
print_r($arr);

>>> Array
(
    [apple] => sweet
    [pear] => tasty
    [grapefruit] => bitter
    [banana] => yellow
)
keithjgrant
A: 

Not entirely sure if this was mentioned, but, the reason this is tricky is because it's non-indexed.

Let's take:

$arrOrig = array(
  'fruit'=>'pear',
  'veg'=>'cucumber',
  'tuber'=>'potato'
);

Get the keys:

$arrKeys = array_keys($arrOrig);
print_r($arrKeys);
Array(
 [0]=>fruit
 [1]=>veg
 [2]=>tuber
)

Get the values:

$arrVals = array_values($arrOrig);
print_r($arrVals);
Array(
  [0]=>pear
  [1]=>cucumber
  [2]=>potato
)

Now you've got 2 arrays that are numerical. Swap the indices of the ones you want to swap, then read the other array back in in the order of the modified numerical array. Let's say we want to swap 'fruit' and 'veg':

$arrKeysFlipped = array_flip($arrKeys);
print_r($arrKeysFlipped);
Array (
 [fruit]=>0
 [veg]=>1
 [tuber]=>2
)
$indexFruit = $arrKeysFlipped['fruit'];
$indexVeg = $arrKeysFlipped['veg'];
$arrKeysFlipped['veg'] = $indexFruit;
$arrKeysFlipped['fruit'] = $indexVeg;
print_r($arrKeysFlipped);
Array (
 [fruit]=>1
 [veg]=>0
 [tuber]=>2
)

Now, you can swap back the array:

$arrKeys = array_flip($arrKeysFlipped);
print_r($arrKeys);
Array (
 [0]=>veg
 [1]=>fruit
 [2]=>tuber
)

Now, you can build an array by going through the oringal array in the 'order' of the rearranged keys.

$arrNew = array ();
foreach($arrKeys as $index=>$key) {
  $arrNew[$key] = $arrOrig[$key];
}
print_r($arrNew);
Array (
 [veg]=>cucumber
 [fruit]=>pear
 [tuber]=>potato
)

I haven't tested this - but this is what I'd expect. Does this at least provide any kind of help? Good luck :)

You could put this into a function $arrNew = array_swap_assoc($key1,$key2,$arrOld);

<?php
if(!function_exists('array_swap_assoc')) {
    function array_swap_assoc($key1='',$key2='',$arrOld=array()) {
       $arrNew = array ();
       if(is_array($arrOld) && count($arrOld) > 0) {
           $arrKeys = array_keys($arrOld);
           $arrFlip = array_flip($arrKeys);
           $indexA = $arrFlip[$key1];
           $indexB = $arrFlip[$key2];
           $arrFlip[$key1]=$indexB;
           $arrFlip[$key2]=$indexA;
           $arrKeys = array_flip($arrFlip);
           foreach($arrKeys as $index=>$key) {
             $arrNew[$key] = $arrOld[$key];
           }
       } else {
           $arrNew = $arrOld;
       }
       return $arrNew;
    }
}
?>

WARNING: Please test and debug this before just using it - no testing has been done at all.

arcaneerudite