Moving array element to top in PHP - php

$arr = array(
'a1'=>'1',
'a2'=>'2'
);
I need to move the a2 to the top, as well as keep the a2 as a key how would I go on about it I can't seem to think a way without messing something up :)

Here is a solution which works correctly both with numeric and string keys:
function move_to_top(&$array, $key) {
$temp = array($key => $array[$key]);
unset($array[$key]);
$array = $temp + $array;
}
It works because arrays in PHP are ordered maps.
Btw, to move an item to bottom use:
function move_to_bottom(&$array, $key) {
$value = $array[$key];
unset($array[$key]);
$array[$key] = $value;
}

You can achieve that this way:
$arr = array(
'a1'=>'1',
'a2'=>'2'
);
end($arr);
$last_key = key($arr);
$last_value = array_pop($arr);
$arr = array_merge(array($last_key => $last_value), $arr);
/*
print_r($arr);
will output (this is tested):
Array ( [a2] => 2 [a1] => 1 )
*/

try this:
$key = 'a3';
$arr = [
'a1' => '1',
'a2' => '2',
'a3' => '3',
'a4' => '4',
'a5' => '5',
'a6' => '6'
];
if (isset($arr[ $key ]))
$arr = [ $key => $arr[ $key ] ] + $arr;
result:
array(
'a3' => '3',
'a1' => '1',
'a2' => '2',
'a4' => '4',
'a5' => '5',
'a6' => '6'
)

Here's a simple one liner to get this done with array_splice() and the union operator:
$arr = array('a1'=>'1', 'a2'=>'2', 'a3' => '3');
$arr = array_splice($arr,array_search('a2',array_keys($arr)),1) + $arr;
Edit:
In retrospect I'm not sure why I wouldn't just do this:
$arr = array('a2' => $arr['a2']) + $arr;
Cleaner, easier and probably faster.

You can also look at array_multisort This lets you use one array to sort another. This could, for example, allow you to externalize a hard-coded ordering of values into a config file.
<?php
$ar1 = array(10, 100, 100, 0);
$ar2 = array(1, 3, 2, 4);
array_multisort($ar1, $ar2);
var_dump($ar1);
var_dump($ar2);
?>
In this example, after sorting, the first array will contain 0, 10, 100, 100. The second array will contain 4, 1, 2, 3. The entries in the second array corresponding to the identical entries in the first array (100 and 100) were sorted as well.
Outputs:
array(4) {
[0]=> int(0)
[1]=> int(10)
[2]=> int(100)
[3]=> int(100)
}
array(4) {
[0]=> int(4)
[1]=> int(1)
[2]=> int(2)
[3]=> int(3)
}

Related

How to add subvalues to a new array? [duplicate]

This question already has answers here:
Is there a function to extract a 'column' from an array in PHP?
(15 answers)
Closed 5 months ago.
I have an array with every containing value being another array with one value. I was looking for a way to flatten the array and succeeded but somehow I am having this feeling that it can be done better. Is this the best way or can it still be improved?
<?php
$array = array(
'1' => array('id' => '123'),
'2' => array('id' => '22'),
'3' => array('id' => '133'),
'4' => array('id' => '143'),
'5' => array('id' => '153'),
);
array_walk_recursive($array, function($v, $k) use (&$result) {
$result[] = $v;
});
You can achieve that using the array_map function:
$func = function($value) {
return $value['id'];
};
$array2 = array_map($func, $array);
Or if you want to keep it in one line do:
$array2 = array_map(function($value) { return $value['id']; }, $array);
This will return the array flattened and keeps your initial keys:
array(5) {
[1]=>
string(3) "123"
[2]=>
string(2) "22"
[3]=>
string(3) "133"
[4]=>
string(3) "143"
[5]=>
string(3) "153"
}
If you don't want to keep the keys, then call the following at the end:
$array2 = array_values($array2);
You can use array_map() passing null as the first argument while unpacking the passed array with the splat operator and grab the first element of the result:
$result = array_map(null, ...$array)[0];
Another option would be to use array_column() which creates an array from a single column of a given multidimensional array - feed it your array and column key, e.g.:
$result = array_column($array, 'id');
Output for either:
print_r($result);
Array
(
[0] => 123
[1] => 22
[2] => 133
[3] => 143
[4] => 153
)
This is what I would do. Its cleaner:
$array = array(
'1' => array('id' => '123'),
'2' => array('id' => '22'),
'3' => array('id' => '133'),
'4' => array('id' => '143'),
'5' => array('id' => '153'),
);
foreach($array as $key => $arr){
$result[] = $arr['id'];
}
If the depth won't ever change a foreach loop would likely be faster. That anonymous function has some overhead to it and it really shows the longer your array gets.
If the depth is variable as well, however, then this is the fastest way to traverse and flatten.

php -Merging an Array

I have two array which i want to merge in a specific way in php.
So i need your help in helping me with it as i tried and failed.
So say i have two arrays:
$array1= array(
"foo" => 3,
"bar" => 2,
"random1" => 4,
);
$array2= array(
"random2" => 3,
"random3" => 4,
"foo" => 6,
);
Now when during merging i would like the common key's values to be added.
So like foo exists in array1 and in array2 so when merging array1 with array 2 i should get "foo" => "9"
I better illustration would be the final array which looks like this:
$array1= array(
"foo" => 9,
"bar" => 2,
"random1" => 4,
"random2" => 3,
"random3" => 4,
);
So again i would like the values of the common keys to be added together and non common keys to be added to array or a new array
I hope i was clear enough
Thanks,
Vidhu
Something like that:
function mergeValues() {
$result = array();
$arraysToMerge = func_get_args();
foreach ($arraysToMerge as $array) {
foreach($array as $key => $value) {
$result[$key] += $value;
}
}
return $result;
}
$res = mergeValues($array1, $array2, $array3); // Can pass any ammount of arrays to a function.
foreach($array1 as $k => $v)
{
If (isset($array2[$k]))
$array1[$k] += $array2[$k];
}
foreach($array2 as $k => $v)
{
If (!isset($array1[$k]))
$array1[$k] = $array2[$k];
}

Replace elements in an associative array using another associative array

How can assign the values from one array to another array? For example:
//array with empty value
$targetArray = array(
'a' => '',
'b' => '',
'c' => '',
'd' => ''
);
// array with non-empty values, but might be missing keys from the target array
$sourceArray = array(
'a'=>'a',
'c'=>'c',
'd'=>'d'
);
The result I would like to see is the following:
$resultArray = array(
'a'=>'a',
'b'=>'',
'c'=>'c',
'd'=>'d'
);
I think the function you are looking for is array_merge.
$resultArray = array_merge($targetArray,$sourceArray);
Use array_merge:
$merged = array_merge($targetArray, $sourceArray);
// will result array('a'=>'a','b'=>'','c'=>'c','d'=>'d');
Use array_merge():
$targetArray = array('a'=>'','b'=>'','c'=>'','d'=>'');
$sourceArray = array('a'=>'a','c'=>'c','d'=>'d');
$result = array_merge( $targetArray, $sourceArray);
This outputs:
array(4) {
["a"]=>
string(1) "a"
["b"]=>
string(0) ""
["c"]=>
string(1) "c"
["d"]=>
string(1) "d"
}
Perhaps a more intuitive/indicative function for this task is array_replace(). It performs identically to array_merge() on associative arrays. (Demo)
var_export(
array_replace($targetArray, $sourceArray)
);
Output:
array (
'a' => 'a',
'b' => '',
'c' => 'c',
'd' => 'd',
)
A similar but not identical result can be achieved with the union operator, but notice that its input parameters are in reverse order and the output array has keys from $targetArray then keys from $sourceArray.
var_export($sourceArray + $targetArray);
Output:
array (
'a' => 'a',
'c' => 'c',
'd' => 'd',
'b' => '',
)

Custom sort of an array

I'm having an array of data like this:
$array = array(
'total_ids' => 0,
'unique_ips' => 0,
'unique_ids' => 0,
'global' => 0,
'total_ips' => 0,
);
I need it to be sorted to this:
$array = array(
'unique_ids' => 0,
'unique_ips' => 0,
'total_ids' => 0,
'total_ips' => 0,
'global' => 0
);
I believe this can be done via uksort, but i can't find the solution of custom_sort function.
This seems rather pointless, can you provide a reason why you need this? I assume it's something to do with a looped output.
$new_array = array(
'unique_ids' => $array['unique_ids'],
'unique_ips' => $array['unique_ips'],
'total_ids' => $array['total_ids'],
'total_ips' =>$array['total_ips'],
'global' => $array['global']
);
$array = $new_array;
It looks like the sorting is done by string length, then by alphabetical ordering. That's not too hard to accomplish using uksort!
function cmp( $a, $b)
{
if( strlen( $a) != strlen( $b))
{
return strlen( $a) < strlen( $b) ? 1 : -1;
}
return strcasecmp( $a, $b);
}
uksort( $array, 'cmp');
Output:
// Before uksort()
array(5) {
["total_ids"]=>
int(0)
["unique_ips"]=>
int(0)
["unique_ids"]=>
int(0)
["global"]=>
int(0)
["total_ips"]=>
int(0)
}
// After uksort()
array(5) {
["unique_ids"]=>
int(0)
["unique_ips"]=>
int(0)
["total_ids"]=>
int(0)
["total_ips"]=>
int(0)
["global"]=>
int(0)
}
See the magic.
I have a set of such arrays but not sorted. I'll be inserting the values to the database with a single query, like INSERT INTO table (unique_ids,unique_ips,total_ids,total_ips,global) VALUES (...),(...),(...) etc. Thats why i need the arrays of this set to be sorted identically
So why not do something like
$array = array(
'total_ids' => 0,
'unique_ips' => 0,
'unique_ids' => 0,
'global' => 0,
'total_ips' => 0,
);
'INSERT INTO table(' . implode(', ', array_keys($array)) . ') VALUES (' . implode(', ', $array) . ')'
Quickly typed it, expect some syntax errors.
This will sort the array descending based on the array key
You want to sort the array descending so you can use this function krsort which will sort the array based on the key descending and I will put them in new array named sorted array
<?php
$array = array(
'total_ids' => 0,
'unique_ips' => 0,
'unique_ids' => 0,
'global' => 0,
'total_ips' => 0,
);
krsort($array);
$sorted_array = array();
foreach ($array as $key => $value) {
$sorted_array[$key] = $value;
}
print_r($sorted_array);
?>

How to add an array value to the middle of an associative array?

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?
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()
The keys I used above are placeholders. Using ksort() will not achieve what I want.
http://www.php.net/manual/en/function.array-splice.php#88896 accomplishes what I'm looking for but I'm looking for something simpler.
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'
Am I missing something?
$key = 'z';
$offset = array_search($key, array_keys($array));
$result = array_merge
(
array_slice($array, 0, $offset),
array('c' => 3),
array_slice($array, $offset, null)
);
Handling of nonexistent keys (appending $data by default):
function insertBeforeKey($array, $key, $data = null)
{
if (($offset = array_search($key, array_keys($array))) === false) // if the key doesn't exist
{
$offset = 0; // should we prepend $array with $data?
$offset = count($array); // or should we append $array with $data? lets pick this one...
}
return array_merge(array_slice($array, 0, $offset), (array) $data, array_slice($array, $offset));
}
Demo:
$array = array('a' => 1, 'z' => 2, 'd' => 4);
// array(4) { ["a"]=> int(1) ["c"]=> int(3) ["z"]=> int(2) ["d"]=> int(4) }
var_dump(insertBeforeKey($array, 'z', array('c' => 3)));
// array(4) { ["a"]=> int(1) ["z"]=> int(2) ["d"]=> int(4) ["c"]=> int(3) }
var_dump(insertBeforeKey($array, 'y', array('c' => 3)));
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 );
According to your original question the best answer I can find is this:
$a = array('a'=>1,'z'=>2,'d'=>4);
$splitIndex = array_search('z', array_keys($a));
$b = array_merge(
array_slice($a, 0, $splitIndex),
array('c' => 3),
array_slice($a, $splitIndex)
);
var_dump($b);
array(4) {
["a"]=>
int(1)
["c"]=>
int(3)
["z"]=>
int(2)
["d"]=>
int(4)
}
Depending on how big your arrays are you will duplicate quite some data in internal memory, regardless if you use this solution or another.
Furthermore your fifth edit seems to indicate that alternatively your SQL query could be improved. What you seem to want to do there would be something like this:
SELECT a, b, CONCAT(a, ' ', b) AS ab FROM ... WHERE ...
If changing your SELECT statement could make the PHP solution redundant, you should definitely go with the modified SQL.
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 automatically:
Array (
...
'pizza' => 12,
'drink' => 5,
'full_meal' => 17,
...
)
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.
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];
}
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];
}
}
For the moment the best i can found to try to minimize the creation of new arrays are these two functions :
the first one try to replace value into the original array and the second one return a new array.
// replace value into the original array
function insert_key_before_inplace(&$base, $beforeKey, $newKey, $value) {
$index = 0;
foreach($base as $key => $val) {
if ($key==$beforeKey) break;
$index++;
}
$end = array_splice($base, $index, count($base)-$index);
$base[$newKey] = $value;
foreach($end as $key => $val) $base[$key] = $val;
}
$array = array('a'=>1,'z'=>2,'d'=>4);
insert_key_before_inplace($array, 'z', 'c', 3);
var_export($array); // array ( 'a' => 1, 'c' => 3, 'z' => 2, 'd' => 4, )
// create new array
function insert_key_before($base, $beforeKey, $newKey, $value) {
$index = 0;
foreach($base as $key => $val) {
if ($key==$beforeKey) break;
$index++;
}
$end = array_splice($base, $index, count($base)-$index);
$base[$newKey] = $value;
return $base+$end;
}
$array = array('a'=>1,'z'=>2,'d'=>4);
$newArray=insert_key_before($array, 'z', 'c', 3);
var_export($array); // ( 'a' => 1, 'z' => 2, 'd' => 4, )
var_export($newArray); // array ( 'a' => 1, 'c' => 3, 'z' => 2, 'd' => 4, )
function putarrayelement(&$array, $arrayobject, $elementposition, $value = null) {
$count = 0;
$return = array();
foreach ($array as $k => $v) {
if ($count == $elementposition) {
if (!$value) {
$value = $count;
}
$return[$value] = $arrayobject;
$inserted = true;
}
$return[$k] = $v;
$count++;
}
if (!$value) {
$value = $count;
}
if (!$inserted){
$return[$value];
}
$array = $return;
return $array;
}
$array = array('a' => 1, 'z' => 2, 'd' => 4);
putarrayelement($array, '3', 1, 'c');
print_r($array);
Great usage of array functions but how about this as a simpler way:
Add a static column to the SQL and then replace it in the resultant array. Order stays the same:
SQL :
Select pizza , drink , 'pizza-drink' as 'pizza-drink' , 28 columns..... From Table
Array :
$result['pizza-drink'] = $result['pizza'] . $result['drink'];
A simplified Alix Axel function if you need to just insert data in nth position:
function array_middle_push( array $array, int $position, array $data ): array {
return array_merge( array_slice( $array, 0, $position ), $data, array_slice( $array, $position ) );
}
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
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

Categories