PHP: compare two arrays and sort by priority - php

I would like to compare two arrays: one is containing the list of possible options and the other array contains priorities.
This is how the two arrays are organized :
foreach ($varsA as $varA) {
foreach ($varsB as $varB) {
$options[$varA][$varB] = $id;
$priority[$varA] = $priority + $priority[$varA];
}
}
this is what $options contains:
array (
1 =>
array (
33307 => 'w',
33313 => '7',
),
2 =>
array (
33307 => 'w',
33313 => '7',
),
3 =>
array (
33307 => 'w',
33313 => '7',
),
4 =>
array (
33307 => '4',
33313 => '7',
),
)
and this is what $priority contains:
array (
1 => 5,
2 => 9,
3 => 9,
4 => 5,
)
I would like to duplicate the duplicates values from $options and keep the one with the uniques with the lowest priority:
The output would be: Array (1, 4) Because 1, 2, 3 are not unique and 1 has the smallest priority.
I was using the following function to remove duplicates but I don't know how I can adapt it to deal with priorities:
super_magic($options) {
$result = array_map("unserialize", array_unique(array_map("serialize", $options)));
foreach ($result as $key => $value) {
if ( is_array($value) ) {
$result[$key] = super_magic($value);
}
}
return $result;
}

This sounds like a very specialized scenario without a foundation specific to PHP. With that being said, i would look into http://php.net/manual/en/ref.array.php that page for specifics on the PHP functions at your disposal for using PHP arrays. I would look into the functions like uksort() and uasort()

for ($x = 1; $x <= count($options); $x++) {
for ($i = 1; $i <= count($options); $i++) {
if (array_key_exists($x, $options) && array_key_exists($i, $options)) {
if ($x != $i) {
$diff = array_diff($options[$x], $options[$i]);
if(empty($diff)) {
if ($priority[$x] >= $priority[$i]){
unset($options[$x]);
}
}
}
}
}
}

Related

PHP - How to turn a single array to multi-dimensional array?

I have a single array like:
array (
'0' => 1,
'1' => 3,
'2' => 4
)
and I want to turn it to a multi-dimensional array like:
array (
'1' =>
array (
'3' => '4'
),
)
Another single array :
array (
'0' => 'a',
'1' => 'b',
'2' => 'c',
'3' => 'd'
)
to :
array (
'a' =>
array (
'b' =>
array (
'c' => 'd'
),
),
),
How can I achieve this?
Note:
The array is dynamic, not always containing 3 or 4 elements.
There are multiple ways to achieve this:
Simple for loop
First, use array_pop() to pop (i.e. store and remove) the last value from the array. Then iterate from the end of the array, successively creating an array with the values (via array_values()):
function transformArray($input) {
$accumulator = array_pop($input);
$values = array_values($input);
for($i = count($input)-1; $i > -1; $i--) {
$accumulator = array($values[$i] => $accumulator);
}
return $accumulator;
}
See it demonstrated in this playground example
foreach loop
Using the code from the previous example, the for loop can be replaced with a foreach loop by utilizing array_reverse(). That way we don't have to worry about when to start and stop the index values, index in to the array, etc.
function transformArray($input) {
$accumulator = array_pop($input);
$values = array_reverse(array_values($input));
foreach($values as $value) {
$accumulator = array($value => $accumulator);
}
return $accumulator;
}
See it demonstrated in this playground example.
Functional approach: array_reduce()
Array_reduce() can be used to simplify the iteration. The first argument of array_reduce() is the input array, the second is a callback function and the third is the initial value. The parameters for the callback function are the accumulator value (from previous iterations) and the array element at the current array index). The initial value is used as the accumulator value for the first iteration, so we can pass the value that was popped from the end of the array.
function transformArray($input) {
$accumulator = array_pop($input);
$values = array_reverse(array_values($input));
return array_reduce($values, function($accumulator, $element) {
return array($element => $accumulator);
}, $accumulator);
}
See it demonstrated in this playground example.
Recursive Approach
Perhaps the simplest technique is to use a recursive function by employing array_shift() to take the first element off the array and return an array with that element as the key and the value is the return value of calling the same function, unless there is only one item, in which case that one item is returned.
function transformArray($input) {
if (count($input) == 1) {
return $input[0];
}
return array(array_shift($input) => transformArray($input));
}
See it demonstrated in this playground example.
If it has always 3 elements:
$temp = array (
'0' => 1,
'1' => 3,
'2' => 4
);
$result = array();
$result[$temp['0']] = array($temp['1'] => $temp['2']);
Although I think there are better strategies, it's possible to use eval() for this purpose:
<?php
/* Example array */
$arr1 = array(
'0' => 'a',
'1' => 'b',
'2' => 'c',
'3' => 'd'
);
$array_string = '';
/* Build array string */
for($i = 0; $i < count($arr1); $i++){
if($i < (count($arr1) - 1)){
$array_string .= 'array ( \''. $arr1[$i] .'\' => ';
} else {
$array_string .= ' \''. $arr1[$i] .'\'';
}
}
/* Close array string */
for($y = 0; $y < count($arr1); $y++){
if($y < (count($arr1) - 2)){
$array_string .= ' ), ';
} else {
$array_string .= ' )';
break;
}
}
/* Evaluate array string as PHP code and put it in $result */
$result = eval("return $array_string;");
/* Print the result */
echo '<pre>';
print_r($result);
echo '</pre>';
?>
Result:
Array
(
[a] => Array
(
[b] => Array
(
[c] => d
)
)
)
But as I said, keep this quote in mind:
If eval() is the answer, you're almost certainly asking the wrong question. -- Rasmus Lerdorf, BDFL of PHP
Ask yourself why you need this. Is there another strategy available for what you want?

I want to add an element to an array at random postion using a loop

I want to add an element to an array at random postion using a loop
I have a fixed ranks like the following
$ranks=array("10","9","8","7","6","5","4","3","2","1");
And I have a random rank position according to a chain,
$agent_ranks=array("10","6","2","1");
which are missing indices
I have calculated the difference between the arrays
$arr_diff=array("9","8","7","5","4","3");
Now I want a dynamic array as a result:
$arr_diff_new=array("0","9","8","7","0","5","4","3","0","0");
How can I add value="0" at the missing indices?
<?php
$ranks=array("10","9","8","7","6","5","4","3","2","1");
$agent_ranks= array_flip( array("10","6","2","1") );
foreach( $ranks as $k=>$v ) {
if ( isset($agent_ranks[$v]) ) {
$ranks[$k] = 0;
}
}
var_export($ranks);
prints
array (
0 => 0,
1 => '9',
2 => '8',
3 => '7',
4 => 0,
5 => '5',
6 => '4',
7 => '3',
8 => 0,
9 => 0,
)
see also: array_flip
You can do it using in_array and for loop:
$ranks=array("10","9","8","7","6","5","4","3","2","1");
$agent_ranks=array("10","6","2","1");
for($i=0;$i < count($ranks); $i++){
if(in_array($ranks[$i], $agent_ranks)){
$newarray[$i] = 0;
}else{
$newarray[$i] = $ranks[$i];
}
}
print_r($newarray);
You can also use in_array in if clause to check if rank is int $agent_ranks and then push 0 or old rank value to new array
$arr_diff_new = array();
foreach($ranks as $rank){
array_push($arr_diff_new,(in_array($rank,$agent_ranks))?0:$rank);
}
You can use array function array_map,
<?php
$array1=array("10","9","8","7","6","5","4","3","2","1");
print_r(array_map('filter',$array1));
function filter($a){
$array2=array("9","8","7","5","4","3");
if(in_array($a,$array2)){
return $a;
}else{
return 0;
}
}
?>
Simply using in_array with foreach loop like as
$ranks=array("10","9","8","7","6","5","4","3","2","1");
$agent_ranks=array("10","6","2","1");
$result = array();
foreach($ranks as $key => $value){
$result[] = in_array($value,$agent_ranks) ? 0 : $value;
}
print_r($result);

Two arrays to one

I have two arrays and I want one, can I add array 2 to array one?
$array1 = array("Germany" => 2, "Belgium"=> 3);
$array2 = array("France" => 4, "Italy"=> 5);
$final_array = {both arrays in one};
is this possible?
Yes, use the array_merge function, like this:
$final_array = array_merge($array1, $array2);
print_r($final_array);
When I run the above script it'll output:
Array (
[Germany] => 2
[Belgium] => 3
[France] => 4
[Italy] => 5
)
Take a quick read here: http://www.php.net/manual/de/function.array-merge.php
Use array_merge like
$final_arr = array_merge($array1 , $array2);
print_r($final_arr);
See this LINK for more
I would like to mention that on duplicated keys array_merge() returns the value from the second array. So, if you have different values with same keys - you should write your own function.
For example:
<?php
$a = array('rund' => '2', 'group' => '3', 'kupon' => 'utre', 'tralala' => 'shtur_kupon');
$b = array('grund' => '2', 'group' => 'ww', 'soup' => '1', 'tralala' => 'fd');
function two_arrays_merge_all_values(array $a, array $b) {
foreach ($b as $b_key => $b_value) {
$a_last_index = count($a);
$current_index = 1;
foreach ($a as $a_key => $a_value) {
if ($a_key === $b_key) {
$unique = uniqid();
$a[$b_key . '_' . $unique] = $b[$b_key];
unset($b[$b_key]);
break;
}
if ($current_index == $a_last_index) {
$a[$b_key] = $b[$b_key];
unset($b[$b_key]);
}
$current_index++;
}
}
return $a;
}

Sort array string-type keys by a custom alphabet?

I want to sort arrays by key in php, but the alphabet that I'm using is not the normal English alphabet -- it's a self-created alphabet. Is this possible?
My alphabet is:
$alphabet = "AjawbpfmnrhHxXsSqkgtTdD =";
The array is like this:
Array (
[=k_0] => Array(
[0] => DI.3,2 &dwA-nTr& #Hrw#
[1] => mA
[2] => =k
[3] => Sfj,t
[4] => =k
[5] => pXr
)
[aA_2] => Array(
[0] => DI.7,4 &dwA-nTr& #Hrw-smA-tA,wj#
[1] => snD
[2] => aA
[3] => Sfj,t
[4] => jt
[5] => jt,w
)
[sqA_1] => Array(
[0] => DI.6,18 &dwA-nTr& #nswt#
[1] => ra
[2] => sqA
[3] => Sfj,t
[4] => =s
[5] => r
)
);
So if I sort this array following my alphabet then the array with the key [=k_0] should be at the end.
You can use the usort() function and provide your own sorting logic.
See php.net for an example.
Edit: use uksort, not usort. See http://www.php.net/manual/en/function.uksort.php. Thanks #Darien!
A slightly modified example from php.net - the original code with an $alphabet mapping added:
function cmp($a, $b)
{
// custom sort order - just swapps 2 and 3.
$alphabet = array (1 => 1, 2 => 3, 3 => 2, 4 => 4, 5 => 5, 6=> 6);
if ($alphabet[$a] == $alphabet[$b]) {
return 0;
}
return ($alphabet[$a] < $alphabet[$b]) ? -1 : 1;
}
$a = array(3 => 'c' , 2 => 'b', 5 => 'e', 6 => 'f', 1=>'a');
uksort($a, "cmp");
foreach ($a as $key => $value) {
echo "$key: $value\n";
}
Given your $alphabet = "AjawbpfmnrhHxXsSqkgtTdD";, and assuming that A<j<a, etc, per your comment, transform each key in the alternative alphabet to a series in the known alphabet, e.g. use a mapping like:
your alphabet: AjawbpfmnrhHxXsSqkgtTdD
'real'alphabet: abcdefghijklmnopqrstuvw
So the key 'Ajaw' => 'abcd', and 'fmnr' => 'ghij', etc. This then turns your keys into something you can sort using conventional php functions. You'd need some way to handle characeters not present in your original alphabet though.
Something like that might work - you'd need two transform functions (from your alphabet to 'real' alphabet and vice versa), and then a comparator for e.g. uksort.
My two cents - thanks for clarifying the original question.
Fortunately, your custom alphabet does not have more characters than the list of single-byte latin letters, so translating is a very simple and readable process.
I recommend that you set up a translation array before you begin sorting, then translate/normalize the keys for the purpose of sorting.
Code: (Demo)
$array = [
'=k_0' => ['test1'],
'aA_2' => ['test2'],
'sqA_1' => ['test3'],
'=kj_0' => ['test4'],
'awA_2' => ['test5'],
'= D_1' => ['test6'],
'sq A_1' => ['test7'],
'sqA_2' => ['test8'],
];
$trans = ['AjawbpfmnrhHxXsSqkgtTdD =', 'abcdefghijklmnopqrstuvwxy'];
uksort(
$array,
function ($a, $b) use ($trans) {
return strtr($a, ...$trans) <=> strtr($b, ...$trans);
}
);
var_export($array);
Output:
array (
'aA_2' =>
array (
0 => 'test2',
),
'awA_2' =>
array (
0 => 'test5',
),
'sqA_1' =>
array (
0 => 'test3',
),
'sqA_2' =>
array (
0 => 'test8',
),
'sq A_1' =>
array (
0 => 'test7',
),
'=k_0' =>
array (
0 => 'test1',
),
'=kj_0' =>
array (
0 => 'test4',
),
'= D_1' =>
array (
0 => 'test6',
),
)
From PHP7.4, the syntax can be reduced using arrow function syntax.
uksort(
$array,
fn($a, $b) => strtr($a, ...$trans) <=> strtr($b, ...$trans)
);
After feedback from #mickmackusa I have updated my example to work with uksrot and answer the question fully
$order = str_split("AjawbpfmnrhHxXsSqkgtTdD");
uksort($arr, function ($a, $b) use ($order) {
$posA = array_search($a, $order);
$posB = array_search($b, $order);
return $posA - $posB;
});
http://sandbox.onlinephpfunctions.com/code/9b6f39b30dcc932517bbe82608dd8a0c8d35b3da
-- original response with usort--
You can use usort() with a custom order array like so
$arr = array("w","b","m","n","x","x","z","T","T","A","A");
$order = array("A","j","a","w","b","p","f","m","n","r","h","H","x","X","s","S","q","k","g","t","T","d","D"," ","=");
usort($arr, function ($a, $b) use ($order) {
$posA = array_search($a, $order);
$posB = array_search($b, $order);
return $posA - $posB;
});
(you could probably just explode the $order string so it's nicer)
I actually just came across this answer which explains it better, and handles if a value is not inside the order array.
And a working example http://sandbox.onlinephpfunctions.com/code/3934aafe93377ec18549d326d6551608436242a7
<?php
$arr = [8,10,12,18,20,7,4,6,2,20,0]; //take array
$a= sortasc($arr); // call function
function sortasc($arr){
for($i=0;$i<=count($arr);$i++){
for($j=1;$j<=count($arr)-1;$j++){
if($arr[$j-1]>$arr[$j]){
$temp = $arr[$j];
$arr[$j]= $arr[$j-1];
$arr[$j-1] = $temp;
}
}
}
return $arr;
}
?>
See this code:
<?php
$arr = array('wr' => 1, 'wrS' => 6, 'wr,w' => 3, 'wr.w' => 4, 'wr-qA' => 2, 'wrs' => 5);
function compare_by_alphabet(array $alphabet, $str1, $str2)
{
$l1 = strlen($str1);
$l2 = strlen($str2);
$c = min($l1, $l2);
for ($i = 0; $i < $c; $i++)
{
$s1 = $str1[$i];
$s2 = $str2[$i];
if ($s1===$s2) continue;
$i1 = array_search($s1, $alphabet);
if ($i1===false) continue;
$i2 = array_search($s2, $alphabet);
if ($i2===false) continue;
if ($i2===$i1) continue;
if ($i1 < $i2) return -1;
else return 1;
}
if ($l1 < $l2) return -1;
elseif ($l1 > $l2) return 1;
return 0;
}
function compare_keys_by_alphabet($a, $b)
{
static $alphabet = array('-', ',', '.', 'A', 'j', 'a', 'w', 'b', 'p', 'f', 'm', 'n', 'r', 'h', 'H', 'x', 'X', 's', 'S', 'q', '‌​k', 'g', 't', 'T', 'd', 'D', '=', '/', '(', ')', '[', ']', '<', '>', '{', '}', '\'', '*', '#', 'I', 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, '&', '#');
return compare_by_alphabet($alphabet, $a, $b);
}
uksort($arr, 'compare_keys_by_alphabet');
print_r($arr);
Result:
Array
(
[wr] => 1
[wr-qA] => 2
[wr,w] => 3
[wr.w] => 4
[wrs] => 5
[wrS] => 6
)

How to insert element into arrays at specific position?

Let's imagine that we have two arrays:
$array_1 = array(
'0' => 'zero',
'1' => 'one',
'2' => 'two',
'3' => 'three',
);
$array_2 = array(
'zero' => '0',
'one' => '1',
'two' => '2',
'three' => '3',
);
Now, I'd like to insert array('sample_key' => 'sample_value') after third element of each array. How can I do it?
array_slice() can be used to extract parts of the array, and the union array operator (+) can recombine the parts.
$res = array_slice($array, 0, 3, true) +
array("my_key" => "my_value") +
array_slice($array, 3, count($array)-3, true);
This example:
$array = array(
'zero' => '0',
'one' => '1',
'two' => '2',
'three' => '3',
);
$res = array_slice($array, 0, 3, true) +
array("my_key" => "my_value") +
array_slice($array, 3, count($array) - 1, true) ;
print_r($res);
gives:
Array
(
[zero] => 0
[one] => 1
[two] => 2
[my_key] => my_value
[three] => 3
)
For your first array, use array_splice():
$array_1 = array(
'0' => 'zero',
'1' => 'one',
'2' => 'two',
'3' => 'three',
);
array_splice($array_1, 3, 0, 'more');
print_r($array_1);
output:
Array(
[0] => zero
[1] => one
[2] => two
[3] => more
[4] => three
)
for the second one there is no order so you just have to do :
$array_2['more'] = '2.5';
print_r($array_2);
And sort the keys by whatever you want.
code:
function insertValueAtPosition($arr, $insertedArray, $position) {
$i = 0;
$new_array=[];
foreach ($arr as $key => $value) {
if ($i == $position) {
foreach ($insertedArray as $ikey => $ivalue) {
$new_array[$ikey] = $ivalue;
}
}
$new_array[$key] = $value;
$i++;
}
return $new_array;
}
example:
$array = ["A"=8, "K"=>3];
$insert_array = ["D"= 9];
insertValueAtPosition($array, $insert_array, $position=2);
// result ====> ["A"=>8, "D"=>9, "K"=>3];
May not really look perfect, but it works.
Here's a simple function that you could use. Just plug n play.
This is Insert By Index, Not By Value.
you can choose to pass the array, or use one that you already have declared.
Newer, shorter version:
function insert($array, $index, $val)
{
$size = count($array); //because I am going to use this more than one time
if (!is_int($index) || $index < 0 || $index > $size)
{
return -1;
}
else
{
$temp = array_slice($array, 0, $index);
$temp[] = $val;
return array_merge($temp, array_slice($array, $index, $size));
}
}
Older, longer version:
function insert($array, $index, $val) { //function decleration
$temp = array(); // this temp array will hold the value
$size = count($array); //because I am going to use this more than one time
// Validation -- validate if index value is proper (you can omit this part)
if (!is_int($index) || $index < 0 || $index > $size) {
echo "Error: Wrong index at Insert. Index: " . $index . " Current Size: " . $size;
echo "<br/>";
return false;
}
//here is the actual insertion code
//slice part of the array from 0 to insertion index
$temp = array_slice($array, 0, $index);//e.g index=5, then slice will result elements [0-4]
//add the value at the end of the temp array// at the insertion index e.g 5
array_push($temp, $val);
//reconnect the remaining part of the array to the current temp
$temp = array_merge($temp, array_slice($array, $index, $size));
$array = $temp;//swap// no need for this if you pass the array cuz you can simply return $temp, but, if u r using a class array for example, this is useful.
return $array; // you can return $temp instead if you don't use class array
}
Usage example:
//1
$result = insert(array(1,2,3,4,5),0, 0);
echo "<pre>";
echo "<br/>";
print_r($result);
echo "</pre>";
//2
$result = insert(array(1,2,3,4,5),2, "a");
echo "<pre>";
print_r($result);
echo "</pre>";
//3
$result = insert(array(1,2,3,4,5) ,4, "b");
echo "<pre>";
print_r($result);
echo "</pre>";
//4
$result = insert(array(1,2,3,4,5),5, 6);
echo "<pre>";
echo "<br/>";
print_r($result);
echo "</pre>";
Expected result:
//1
Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 3
[4] => 4
[5] => 5
)
//2
Array
(
[0] => 1
[1] => 2
[2] => a
[3] => 3
[4] => 4
[5] => 5
)
//3
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => b
[5] => 5
)
//4
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
)
$list = array(
'Tunisia' => 'Tunis',
'Germany' => 'Berlin',
'Italy' => 'Rom',
'Egypt' => 'Cairo'
);
$afterIndex = 2;
$newVal= array('Palestine' => 'Jerusalem');
$newList = array_merge(array_slice($list,0,$afterIndex+1), $newVal,array_slice($list,$afterIndex+1));
This function supports:
both numeric and assoc keys
insert before or after the founded key
append to the end of array if key isn't founded
function insert_into_array( $array, $search_key, $insert_key, $insert_value, $insert_after_founded_key = true, $append_if_not_found = false ) {
$new_array = array();
foreach( $array as $key => $value ){
// INSERT BEFORE THE CURRENT KEY?
// ONLY IF CURRENT KEY IS THE KEY WE ARE SEARCHING FOR, AND WE WANT TO INSERT BEFORE THAT FOUNDED KEY
if( $key === $search_key && ! $insert_after_founded_key )
$new_array[ $insert_key ] = $insert_value;
// COPY THE CURRENT KEY/VALUE FROM OLD ARRAY TO A NEW ARRAY
$new_array[ $key ] = $value;
// INSERT AFTER THE CURRENT KEY?
// ONLY IF CURRENT KEY IS THE KEY WE ARE SEARCHING FOR, AND WE WANT TO INSERT AFTER THAT FOUNDED KEY
if( $key === $search_key && $insert_after_founded_key )
$new_array[ $insert_key ] = $insert_value;
}
// APPEND IF KEY ISNT FOUNDED
if( $append_if_not_found && count( $array ) == count( $new_array ) )
$new_array[ $insert_key ] = $insert_value;
return $new_array;
}
USAGE:
$array1 = array(
0 => 'zero',
1 => 'one',
2 => 'two',
3 => 'three',
4 => 'four'
);
$array2 = array(
'zero' => '# 0',
'one' => '# 1',
'two' => '# 2',
'three' => '# 3',
'four' => '# 4'
);
$array3 = array(
0 => 'zero',
1 => 'one',
64 => '64',
3 => 'three',
4 => 'four'
);
// INSERT AFTER WITH NUMERIC KEYS
print_r( insert_into_array( $array1, 3, 'three+', 'three+ value') );
// INSERT AFTER WITH ASSOC KEYS
print_r( insert_into_array( $array2, 'three', 'three+', 'three+ value') );
// INSERT BEFORE
print_r( insert_into_array( $array3, 64, 'before-64', 'before-64 value', false) );
// APPEND IF SEARCH KEY ISNT FOUNDED
print_r( insert_into_array( $array3, 'undefined assoc key', 'new key', 'new value', true, true) );
RESULTS:
Array
(
[0] => zero
[1] => one
[2] => two
[3] => three
[three+] => three+ value
[4] => four
)
Array
(
[zero] => # 0
[one] => # 1
[two] => # 2
[three] => # 3
[three+] => three+ value
[four] => # 4
)
Array
(
[0] => zero
[1] => one
[before-64] => before-64 value
[64] => 64
[3] => three
[4] => four
)
Array
(
[0] => zero
[1] => one
[64] => 64
[3] => three
[4] => four
[new key] => new value
)
Simplest solution, if you want to insert (an element or array) after a certain key:
function array_splice_after_key($array, $key, $array_to_insert)
{
$key_pos = array_search($key, array_keys($array));
if($key_pos !== false){
$key_pos++;
$second_array = array_splice($array, $key_pos);
$array = array_merge($array, $array_to_insert, $second_array);
}
return $array;
}
So, if you have:
$array = [
'one' => 1,
'three' => 3
];
$array_to_insert = ['two' => 2];
And execute:
$result_array = array_splice_after_key($array, 'one', $array_to_insert);
You'll have:
Array (
['one'] => 1
['two'] => 2
['three'] => 3
)
I recently wrote a function to do something similar to what it sounds like you're attempting, it's a similar approach to clasvdb's answer.
function magic_insert($index,$value,$input_array ) {
if (isset($input_array[$index])) {
$output_array = array($index=>$value);
foreach($input_array as $k=>$v) {
if ($k<$index) {
$output_array[$k] = $v;
} else {
if (isset($output_array[$k]) ) {
$output_array[$k+1] = $v;
} else {
$output_array[$k] = $v;
}
}
}
} else {
$output_array = $input_array;
$output_array[$index] = $value;
}
ksort($output_array);
return $output_array;
}
Basically it inserts at a specific point, but avoids overwriting by shifting all items down.
Using array_splice instead of array_slice gives one less function call.
$toto = array(
'zero' => '0',
'one' => '1',
'two' => '2',
'three' => '3'
);
$ret = array_splice($toto, 3 );
$toto = $toto + array("my_key" => "my_value") + $ret;
print_r($toto);
If you don't know that you want to insert it at position #3, but you know the key that you want to insert it after, I cooked up this little function after seeing this question.
/**
* Inserts any number of scalars or arrays at the point
* in the haystack immediately after the search key ($needle) was found,
* or at the end if the needle is not found or not supplied.
* Modifies $haystack in place.
* #param array &$haystack the associative array to search. This will be modified by the function
* #param string $needle the key to search for
* #param mixed $stuff one or more arrays or scalars to be inserted into $haystack
* #return int the index at which $needle was found
*/
function array_insert_after(&$haystack, $needle = '', $stuff){
if (! is_array($haystack) ) return $haystack;
$new_array = array();
for ($i = 2; $i < func_num_args(); ++$i){
$arg = func_get_arg($i);
if (is_array($arg)) $new_array = array_merge($new_array, $arg);
else $new_array[] = $arg;
}
$i = 0;
foreach($haystack as $key => $value){
++$i;
if ($key == $needle) break;
}
$haystack = array_merge(array_slice($haystack, 0, $i, true), $new_array, array_slice($haystack, $i, null, true));
return $i;
}
Here's a codepad fiddle to see it in action: http://codepad.org/5WlKFKfz
Note: array_splice() would have been a lot more efficient than array_merge(array_slice()) but then the keys of your inserted arrays would have been lost. Sigh.
Cleaner approach (based on fluidity of use and less code).
/**
* Insert data at position given the target key.
*
* #param array $array
* #param mixed $target_key
* #param mixed $insert_key
* #param mixed $insert_val
* #param bool $insert_after
* #param bool $append_on_fail
* #param array $out
* #return array
*/
function array_insert(
array $array,
$target_key,
$insert_key,
$insert_val = null,
$insert_after = true,
$append_on_fail = false,
$out = [])
{
foreach ($array as $key => $value) {
if ($insert_after) $out[$key] = $value;
if ($key == $target_key) $out[$insert_key] = $insert_val;
if (!$insert_after) $out[$key] = $value;
}
if (!isset($array[$target_key]) && $append_on_fail) {
$out[$insert_key] = $insert_val;
}
return $out;
}
Usage:
$colors = [
'blue' => 'Blue',
'green' => 'Green',
'orange' => 'Orange',
];
$colors = array_insert($colors, 'blue', 'pink', 'Pink');
die(var_dump($colors));
This is an old question, but I posted a comment in 2014 and frequently come back to this. I thought I would leave a full answer. This isn't the shortest solution but it is quite easy to understand.
Insert a new value into an associative array, at a numbered position, preserving keys, and preserving order.
$columns = array(
'id' => 'ID',
'name' => 'Name',
'email' => 'Email',
'count' => 'Number of posts'
);
$columns = array_merge(
array_slice( $columns, 0, 3, true ), // The first 3 items from the old array
array( 'subscribed' => 'Subscribed' ), // New value to add after the 3rd item
array_slice( $columns, 3, null, true ) // Other items after the 3rd
);
print_r( $columns );
/*
Array (
[id] => ID
[name] => Name
[email] => Email
[subscribed] => Subscribed
[count] => Number of posts
)
*/
I do that as
$slightly_damaged = array_merge(
array_slice($slightly_damaged, 0, 4, true) + ["4" => "0.0"],
array_slice($slightly_damaged, 4, count($slightly_damaged) - 4, true)
);
This is another solution in PHP 7.1
/**
* #param array $input Input array to add items to
* #param array $items Items to insert (as an array)
* #param int $position Position to inject items from (starts from 0)
*
* #return array
*/
function arrayInject( array $input, array $items, int $position ): array
{
if (0 >= $position) {
return array_merge($items, $input);
}
if ($position >= count($input)) {
return array_merge($input, $items);
}
return array_merge(
array_slice($input, 0, $position, true),
$items,
array_slice($input, $position, null, true)
);
}
I just created an ArrayHelper class that would make this very easy for numeric indexes.
class ArrayHelper
{
/*
Inserts a value at the given position or throws an exception if
the position is out of range.
This function will push the current values up in index. ex. if
you insert at index 1 then the previous value at index 1 will
be pushed to index 2 and so on.
$pos: The position where the inserted value should be placed.
Starts at 0.
*/
public static function insertValueAtPos(array &$array, $pos, $value) {
$maxIndex = count($array)-1;
if ($pos === 0) {
array_unshift($array, $value);
} elseif (($pos > 0) && ($pos <= $maxIndex)) {
$firstHalf = array_slice($array, 0, $pos);
$secondHalf = array_slice($array, $pos);
$array = array_merge($firstHalf, array($value), $secondHalf);
} else {
throw new IndexOutOfBoundsException();
}
}
}
Example:
$array = array('a', 'b', 'c', 'd', 'e');
$insertValue = 'insert';
\ArrayHelper::insertValueAtPos($array, 3, $insertValue);
Beginning $array:
Array (
[0] => a
[1] => b
[2] => c
[3] => d
[4] => e
)
Result:
Array (
[0] => a
[1] => b
[2] => c
[3] => insert
[4] => d
[5] => e
)
This is better method how insert item to array on some position.
function arrayInsert($array, $item, $position)
{
$begin = array_slice($array, 0, $position);
array_push($begin, $item);
$end = array_slice($array, $position);
$resultArray = array_merge($begin, $end);
return $resultArray;
}
I needed something that could do an insert before, replace, after the key; and add at the start or end of the array if target key is not found. Default is to insert after the key.
New Function
/**
* Insert element into an array at a specific key.
*
* #param array $input_array
* The original array.
* #param array $insert
* The element that is getting inserted; array(key => value).
* #param string $target_key
* The key name.
* #param int $location
* 1 is after, 0 is replace, -1 is before.
*
* #return array
* The new array with the element merged in.
*/
function insert_into_array_at_key(array $input_array, array $insert, $target_key, $location = 1) {
$output = array();
$new_value = reset($insert);
$new_key = key($insert);
foreach ($input_array as $key => $value) {
if ($key === $target_key) {
// Insert before.
if ($location == -1) {
$output[$new_key] = $new_value;
$output[$key] = $value;
}
// Replace.
if ($location == 0) {
$output[$new_key] = $new_value;
}
// After.
if ($location == 1) {
$output[$key] = $value;
$output[$new_key] = $new_value;
}
}
else {
// Pick next key if there is an number collision.
if (is_numeric($key)) {
while (isset($output[$key])) {
$key++;
}
}
$output[$key] = $value;
}
}
// Add to array if not found.
if (!isset($output[$new_key])) {
// Before everything.
if ($location == -1) {
$output = $insert + $output;
}
// After everything.
if ($location == 1) {
$output[$new_key] = $new_value;
}
}
return $output;
}
Input code
$array_1 = array(
'0' => 'zero',
'1' => 'one',
'2' => 'two',
'3' => 'three',
);
$array_2 = array(
'zero' => '0',
'one' => '1',
'two' => '2',
'three' => '3',
);
$array_1 = insert_into_array_at_key($array_1, array('sample_key' => 'sample_value'), 2, 1);
print_r($array_1);
$array_2 = insert_into_array_at_key($array_2, array('sample_key' => 'sample_value'), 'two', 1);
print_r($array_2);
Output
Array
(
[0] => zero
[1] => one
[2] => two
[sample_key] => sample_value
[3] => three
)
Array
(
[zero] => 0
[one] => 1
[two] => 2
[sample_key] => sample_value
[three] => 3
)
Very simple 2 string answer to your question:
$array_1 = array(
'0' => 'zero',
'1' => 'one',
'2' => 'two',
'3' => 'three',
);
At first you insert anything to your third element with array_splice and then assign a value to this element:
array_splice($array_1, 3, 0 , true);
$array_1[3] = array('sample_key' => 'sample_value');
Not as concrete as the answer of Artefacto, but based in his suggestion of using array_slice(), I wrote the next function:
function arrayInsert($target, $byKey, $byOffset, $valuesToInsert, $afterKey) {
if (isset($byKey)) {
if (is_numeric($byKey)) $byKey = (int)floor($byKey);
$offset = 0;
foreach ($target as $key => $value) {
if ($key === $byKey) break;
$offset++;
}
if ($afterKey) $offset++;
} else {
$offset = $byOffset;
}
$targetLength = count($target);
$targetA = array_slice($target, 0, $offset, true);
$targetB = array_slice($target, $offset, $targetLength, true);
return array_merge($targetA, $valuesToInsert, $targetB);
}
Features:
Inserting one or múltiple values
Inserting key value pair(s)
Inserting before/after the key, or by offset
Usage examples:
$target = [
'banana' => 12,
'potatoe' => 6,
'watermelon' => 8,
'apple' => 7,
2 => 21,
'pear' => 6
];
// Values must be nested in an array
$insertValues = [
'orange' => 0,
'lemon' => 3,
3
];
// By key
// Third parameter is not applicable
// Insert after 2 (before 'pear')
var_dump(arrayInsert($target, 2, null, $valuesToInsert, true));
// Insert before 'watermelon'
var_dump(arrayInsert($target, 'watermelon', null, $valuesToInsert, false));
// By offset
// Second and last parameter are not applicable
// Insert in position 2 (zero based i.e. before 'watermelon')
var_dump(arrayInsert($target, null, 2, $valuesToInsert, null));
In case you are just looking to insert an item into an array at a certain position (based on #clausvdb answer):
function array_insert($arr, $insert, $position) {
$i = 0;
$ret = array();
foreach ($arr as $key => $value) {
if ($i == $position) {
$ret[] = $insert;
}
$ret[] = $value;
$i++;
}
return $ret;
}
Here is my version:
/**
*
* Insert an element after an index in an array
* #param array $array
* #param string|int $key
* #param mixed $value
* #param string|int $offset
* #return mixed
*/
function array_splice_associative($array, $key, $value, $offset) {
if (!is_array($array)) {
return $array;
}
if (array_key_exists($key, $array)) {
unset($array[$key]);
}
$return = array();
$inserted = false;
foreach ($array as $k => $v) {
$return[$k] = $v;
if ($k == $offset && !$inserted) {
$return[$key] = $value;
$inserted = true;
}
}
if (!$inserted) {
$return[$key] = $value;
}
return $return;
}
try this one ===
$key_pos=0;
$a1=array("a"=>"red", "b"=>"green", "c"=>"blue", "d"=>"yellow");
$arrkey=array_keys($a1);
array_walk($arrkey,function($val,$key) use(&$key_pos) {
if($val=='b')
{
$key_pos=$key;
}
});
$a2=array("e"=>"purple");
$newArray = array_slice($a1, 0, $key_pos, true) + $a2 +
array_slice($a1, $key_pos, NULL, true);
print_r($newArray);
Output
Array (
[a] => red
[e] => purple
[b] => green
[c] => blue
[d] => yellow )
This can be done by array.splice(). Please note array_splice or array_merge doesn't preserve keys for associative arrays. So array_slice is used and '+' operator is used for concatenating the two arrays.
More details here
$array_1 = array(
'0' => 'zero',
'1' => 'one',
'2' => 'two',
'3' => 'three',
);
$array_2 = array(
'zero' => '0',
'one' => '1',
'two' => '2',
'three' => '3',
);
$index = 2;
$finalArray = array_slice($array_1, 0, $index, true) +
$array2 +
array_slice($array_2, $index, NULL, true);
print_r($finalArray);
/*
Array
(
[0] => zero
[1] => one
[10] => grapes
[z] => mangoes
[two] => 2
[three] => 3
)
*/
I've created a function (PHP 8.1), which allows you to insert items to associative or numeric arrays:
function insertItemsToPosition(array $array, string|int $insertAfterPosition, array $itemsToAdd): array
{
$insertAfterIndex = array_search($insertAfterPosition, array_keys($array), true);
if ($insertAfterIndex === false) {
throw new \UnexpectedValueException(sprintf('You try to insert items to an array after the key "%s", but this key is not existing in given array. Available keys are: %s', $insertAfterPosition, implode(', ', array_keys($array))));
}
$itemsBefore = array_slice($array, 0, $insertAfterIndex + 1);
$itemsAfter = array_slice($array, $insertAfterIndex + 1);
return $itemsBefore + $itemsToAdd + $itemsAfter;
}
You can insert elements during a foreach loop, since this loop works on a copy of the original array, but you have to keep track of the number of inserted lines (I call this "bloat" in this code):
$bloat=0;
foreach ($Lines as $n=>$Line)
{
if (MustInsertLineHere($Line))
{
array_splice($Lines,$n+$bloat,0,"string to insert");
++$bloat;
}
}
Obviously, you can generalize this "bloat" idea to handle arbitrary insertions and deletions during the foreach loop.

Categories