tags:

views:

126

answers:

8

Lets say I have this array:

$array = array('a'=>1,'z'=>2,'d'=>4);

Later in the script, I want to add the value 'c'=>3 before 'z'. How can I do this?

EDIT: Yes, the order is important. When I run a foreach() through the array, I do NOT want this newly added value added to the end of the array. I am getting this array from a mysql_fetch_assoc()

EDIT 2: The keys I used above are placeholders. Using ksort() will not achieve what I want.

EDIT 3: http://www.php.net/manual/en/function.array-splice.php#88896 accomplishes what I'm looking for but I'm looking for something simpler.

EDIT 4: Thanks for the downvotes. I gave feedback to your answers and you couldn't help, so you downvoted and requested to close the question because you didn't know the answer. Thanks.

EDIT 5: Take a sample db table with about 30 columns. I get this data using mysql_fetch_assoc(). In this new array, after column 'pizza' and 'drink', I want to add a new column 'full_dinner' that combines the values of 'pizza' and 'drink' so that when I run a foreach() on the said array, 'full_dinner' comes directly after 'drink'

A: 

Try this

$array['c']=3;

An associative array is not ordered by default, but if you wanted to sort them alphabetically you could use ksort() to sort the array by it's key.

If you check out the PHP article for ksort() you will se it's easy to sort an array by its key, for example:

<?php
$fruits = array("d"=>"lemon", "a"=>"orange", "b"=>"banana", "c"=>"apple");
ksort($fruits);
foreach ($fruits as $key => $val) {
    echo "$key = $val\n";
}
?>

// The above example will output:
a = orange
b = banana
c = apple
d = lemon
ILMV
This answer will not work. See my edit above.
Citizen
Like I said, use `ksort()`, that will reorder your array by ke, so instead of `a, b, d, c` it will be `a, b, c, d`
ILMV
This answer will not work. see edit 2.
Citizen
Yes it will, each array item has a key, and therefore `ksort()` will sort it.
ILMV
What do you mean by placeholders? Form the information you've given this answer should work.
ILMV
I'm getting the info from a mysql_fetch_assoc(). The keys are not in alphabetical order.
Citizen
Ok well it was nice of you to explain that in your question. How is anyone supposed to give an accurate answer when the question isn't telling the entire story.
ILMV
I did via edit.
Citizen
Ok then so if you've got 50 records, where is your new records going to be inserted? What are you rules, will it always go right before the very end?
ILMV
What I have is I know the exact key that I want to place a record after in an associative array.
Citizen
Again, it was nice of you to specifically say then when you asked the question, of course the example a, b, d, c was going to throw people off. And have you downvoted some of my questions? I don't know why you're calling a 'newbie' when you've had to edit your own question 5 times to get the correct answer!
ILMV
A: 

Associative arrays are not ordered, so you can simply add with $array['c'] = 3.

If order is important, one option is switch to a data structure more like:

$array = array(
   array('a' => 1),
   array('b' => 2)
   array('d' => 4)
);

Then, use array_splice($array, 2, 0, array('c' => 3)) to insert at position 2. See manual on array_splice.

spoulson
This answer will not work. See my edit above.
Citizen
This answer also isn't very dynamic, it will only work if you want to insert the new array value into position 3.
ILMV
From the question: "Later in the script, I want to add the value 'c'=>3 before 'd'. How can I do this?"
spoulson
@ILMV At least spoulson's solution works similarly to what I need. I really want to keep the current associations so this wont work but its a lot closer than ILMV's "answer" that any php newbie would have already known.
Citizen
A: 

An associative array is made by hashing the key and so are not ordered as you think with an alphabetical order, or numerical order but only with the result of the hashing function

Patrick
Wont work. See my edit above.
Citizen
A: 

you can add it by doing

$array['c']=3;

and if you absolutely want it sorted for printing purposes, you can use php's ksort($array) function

if the keys are not sortable by ksort, then you will have to create your own sort by using php's uasort function. see examples here

http://php.net/manual/en/function.uasort.php

zaphod
Is it possible to use uasort on a single record? I have hundreds of records in this array.
Citizen
in uasort, what you're doing is feeding it a a comparator for your keys. your array can be as big or small as you want it to be.
zaphod
A: 

An alternative approach is to supplement the associative array structure with an ordered index that determines the iterative order of keys. For instance:

$index = array('a','b','d');

// Add new value and update index
$array['c'] = 3;
array_splice($index, 2, 0, 'c');

// Iterate the array in order
foreach $index as $key {
   $value = $array[$key];
}
spoulson
This is not exactly a simple solution. I might as well unset all the variables after my location, add the variable, and then readd the unset'd variables.
Citizen
+2  A: 

A simple approach to this is to iterate through the original array, constructing a new one as you go:

function InsertBeforeKey( $originalArray, $originalKey, $insertKey, $insertValue ) {

    $newArray = array();
    $inserted = false;

    foreach( $originalArray as $key => $value ) {

        if( !$inserted && $key == $originalKey ) {
            $newArray[ $insertKey ] = $insertValue;
            $inserted = true;
        }

        $newArray[ $key ] = $value;

    }

    return $newArray;

}

Then simply call

$array = InsertBeforeKey( $array, 'd', 'c', 3 );
This does it, but I find it hard to believe that a simpler method does not exist.
Citizen
In my answer below, I added an option based on ArrayObject that makes the interface to this simpler, but it probably executes slower. You could always modify it to use this iteration approach instead of the sort approach.
Peter Bailey
A: 
function insertValue($oldArray, $newKey, $newValue, $followingKey) {

    $newArray = array ();
    foreach (array_keys($oldArray) as $k) {
        if ($k == $followingKey)
            $newArray[$newKey] = $newValue;
        $newArray[$k] = $oldArray [$k];
    }

    return $newArray;
}

You call it as

insertValue($array, 'c', '3', 'z')

As for Edit 5:

edit your sql, so that it reads

SELECT ..., pizza, drink, pizza+drink as full_meal, ... FROM ....

and you have the column automagically:

Array (
  ...
  'pizza' => 12,
  'drink' => 5,
  'full_meal' => 17,
  ...
)
Cassy
A: 

You can define your own sortmap when doing a bubble-sort by key. It's probably not terribly efficient but it works.

<pre>
<?php

$array = array('a'=>1,'z'=>2,'d'=>4);

$array['c'] = 3;

print_r( $array );

uksort( $array, 'sorter' );

print_r( $array );

function sorter( $a, $b )
{
    static $ordinality = array(
        'a' => 1
      , 'c' => 2
      , 'z' => 3
      , 'd' => 4
    );
    return $ordinality[$a] - $ordinality[$b];
}

?>
</pre>

Here's an approach based on ArrayObject using this same concept

$array = new CitizenArray( array('a'=>1,'z'=>2,'d'=>4) );
$array['c'] = 3;

foreach ( $array as $key => $value )
{
    echo "$key: $value <br>";
}

class CitizenArray extends ArrayObject
{
    static protected $ordinality = array(
        'a' => 1
      , 'c' => 2
      , 'z' => 3
      , 'd' => 4
    );

    function offsetSet( $key, $value )
    {
        parent::offsetSet( $key, $value );
        $this->uksort( array( $this, 'sorter' ) );
    }

    function sorter( $a, $b )
    {
        return self::$ordinality[$a] - self::$ordinality[$b];
    }
}
Peter Bailey
While your code may be correct, I don't believe it applies to question at hand. @Citizen is looking to insert relative to a specific key, not have an implicit ordering over all possible keys.
I think it's arguable that, in some circumstances, they are the exact same thing. There's actually not enough info in his question to determine which he's implying 100%.
Peter Bailey
Although not a perfect solution, I thought it was informative and at the very least deserves not to have a negative vote :) Thanks peter for the extra info.
Citizen