How to delete key from array and update index? - php

$array = array('a', 'b','c');
unset($array[0]);
var_dump($array);
Yields:
array(1) {
[1]=>
'b'
'c'
}
How do I, remove array[0] to get ['bb','cc'] (no empty keys):
array(1) {
'b'
'c'
}

Check this:
$array = array('a', 'b','c');
unset($array[0]);
$array = array_values($array); //reindexing

Take a look at array_splice()
$array = array_splice($array, 0, 1);
If you happen to be removing the first element specifically (and not an arbitrary element in the middle of the array), array_shift() is more appropriate.

Related

reverse first array element with last

I'm trying to reverse first element of array given in parameter of my function with last element.
here is my try so far:
$my_array = [0, 1, 2, 3, 4];
function reverse_start_with_last(array &$arr)
{
$arr[0] = end($arr);
$last = end($arr);
$last = reset($arr);
print_r($arr);
static $callingnumber = 0;
$callingnumber++;
echo '<br><br>' . $callingnumber;
}
reverse_start_with_last($my_array);
it outputs:
Array ( [0] => 4 [1] => 1 [2] => 2 [3] => 3 [4] => 4 ).
so as you can see zero is reversed with 4 but 4 is not reversed with 0..
Thanks in advance !
There are a few ways to do it, the problem is that your code overwrites the start before it stores it and tries to move it. This code takes the value, then overwrites it and then updates the last item...
function reverse_start_with_last(array &$arr)
{
$first = $arr[0];
$arr[0] = end($arr);
$arr[count($arr)-1] = $first;
print_r($arr);
}
reverse_start_with_last($my_array);
This assumes a numerically indexed array and not any other form of indexing.
This function swap the first with the last element of the array.
function array_change_first_last(array &$arr)
{
$last = end($arr);
$arr[key($arr)] = reset($arr);
$arr[key($arr)] = $last;
}
$my_array = [0, 1, 2, 3, 4];
array_change_first_last($my_array);
This function works with numeric and associative arrays alike. The keys remain, only the values ​​are exchanged.
$ass_array = ['a' => 0, 'b' => 1, 'c' => 2, 'd' => 3, 'z'=> 4];
array_change_first_last($ass_array);
Result:
array(5) { ["a"]=> int(4) ["b"]=> int(1) ["c"]=> int(2) ["d"]=> int(3) ["z"]=> int(0) }
You can shift the first element and pop the last and store them and then unshift the last and push the first
$my_array = [0, 1, 2, 3, 4];
function reverse_start_with_last(array &$arr)
{
$first = array_shift($arr); // remove the first element and store it
$last = array_pop($arr); // remove the last and store it
array_unshift($arr, $last); // add the last at the beginning of the array
array_push($arr, $first); // add the first at the end of the array
}
reverse_start_with_last($my_array);
print_r($my_array)

How to set a list of values as keys in a multidimensional associative array?

I would like to convert a list of values such as:
$foo = ['a', 'b', 'c'];
into a list of traversing array keys such as:
$bar['a']['b']['c'] = 123;
How I can create an associative array which keys are based on a set values stored in another array?
You can make it with reference. Try this code, live demo
<?php
$foo = ['a', 'b', 'c'];
$array = [];
$current = &$array;
foreach($foo as $key) {
#$current = &$current[$key];
}
$current = 123;
print_r($array);
I would do it like this:
$foo = ['a', 'b', 'c'];
$val = '123';
foreach (array_reverse($foo) as $k => $v) {
$bar = [$v => $k ? $bar : $val];
}
We are iterating over the array in reverse and assigning the innermost value first, then building the array from the inside out.
Here is another option: Create a temporary parsable string (by extracting the first value, then appending the remaining values as square bracket wrapped strings), call parse_str(), and set the output variable as $bar.
Code: (Demo)
$foo = ['a', 'b', 'c'];
$val=123;
parse_str(array_shift($foo).'['.implode('][',$foo)."]=$val",$bar);
// built string: `a[b][c]=123`
var_export($bar);
Output:
array (
'a' =>
array (
'b' =>
array (
'c' => '123',
),
),
)
If that first method feels too hack-ish, the following recursive method is a stable approach:
Code: (Demo)
function nest_assoc($keys,$value){
return [array_shift($keys) => (empty($keys) ? $value : nest_assoc($keys,$value))];
// ^^^^^^^^^^^^^^^^^^--------------------------------------------------------extract leading key value, modify $keys
// check if any keys left-----^^^^^^^^^^^^
// no more keys, use the value---------------^^^^^^
// recurse to write the subarray contents-------------^^^^^^^^^^^^^^^^^^^^^^^^^
}
$foo=['a','b','c'];
$val=123;
var_export(nest_assoc($foo,$val));
// same output

How to merge two arrays by taking over only values from the second array that has the same keys as the first one?

I'd like to merge two arrays with each other:
$filtered = array(1 => 'a', 3 => 'c');
$changed = array(2 => 'b*', 3 => 'c*');
Whereas the merge should include all elements of $filtered and all those elements of $changed that have a corresponding key in $filtered:
$merged = array(1 => 'a', 3 => 'c*');
array_merge($filtered, $changed) would add the additional keys of $changed into $filtered as well. So it does not really fit.
I know that I can use $keys = array_intersect_key($filtered, $changed) to get the keys that exist in both arrays which is already half of the work.
However I'm wondering if there is any (native) function that can reduce the $changed array into an array with the $keys specified by array_intersect_key? I know I can use array_filter with a callback function and check against $keys therein, but there is probably some other purely native function to extract only those elements from an array of which the keys can be specified?
I'm asking because the native functions are often much faster than array_filter with a callback.
This should do it, if I'm understanding your logic correctly:
array_intersect_key($changed, $filtered) + $filtered
Implementation:
$filtered = array(1 => 'a', 3 => 'c');
$changed = array(2 => 'b*', 3 => 'c*');
$expected = array(1 => 'a', 3 => 'c*');
$actual = array_key_merge_deceze($filtered, $changed);
var_dump($expected, $actual);
function array_key_merge_deceze($filtered, $changed) {
$merged = array_intersect_key($changed, $filtered) + $filtered;
ksort($merged);
return $merged;
}
Output:
Expected:
array(2) {
[1]=>
string(1) "a"
[3]=>
string(2) "c*"
}
Actual:
array(2) {
[1]=>
string(1) "a"
[3]=>
string(2) "c*"
}
if you want the second array ($b) to be the pattern that indicates that if there is only the key there, then you could also try this
$new_array = array_intersect_key( $filtered, $changed ) + $changed;
If your keys are non-numeric (which yours are not, so this is not a solution to your exact question), then you can use this technique:
$filtered = array('a' => 'a', 'c' => 'c');
$changed = array('b' => 'b*', 'c' => 'c*');
$merged = array_slice(array_merge($filtered, $changed), 0, count($filtered));
Result:
Array
(
[a] => a
[c] => c*
)
This works because for non-numeric keys, array_merge overwrites values for existing keys, and appends the keys in $changed to the end of the new array. So we can simply discard any keys from the end of the merged array more than the count of the original array.
Since this applies to the same question but with different key types I thought I'd provide it.
If you use this with numeric keys then the result is simply the original array ($filtered in this case) with re-indexed keys (IE as if you used array_values).

PHP append one array to another (not array_push or +)

How to append one array to another without comparing their keys?
$a = array( 'a', 'b' );
$b = array( 'c', 'd' );
At the end it should be: Array( [0]=>a [1]=>b [2]=>c [3]=>d )
If I use something like [] or array_push, it will cause one of these results:
Array( [0]=>a [1]=>b [2]=>Array( [0]=>c [1]=>d ) )
//or
Array( [0]=>c [1]=>d )
It just should be something, doing this, but in a more elegant way:
foreach ( $b AS $var )
$a[] = $var;
array_merge is the elegant way:
$a = array('a', 'b');
$b = array('c', 'd');
$merge = array_merge($a, $b);
// $merge is now equals to array('a','b','c','d');
Doing something like:
$merge = $a + $b;
// $merge now equals array('a','b')
Will not work, because the + operator does not actually merge them. If they $a has the same keys as $b, it won't do anything.
Another way to do this in PHP 5.6+ would be to use the ... token
$a = array('a', 'b');
$b = array('c', 'd');
array_push($a, ...$b);
// $a is now equals to array('a','b','c','d');
This will also work with any Traversable
$a = array('a', 'b');
$b = new ArrayIterator(array('c', 'd'));
array_push($a, ...$b);
// $a is now equals to array('a','b','c','d');
A warning though:
in PHP versions before 7.3 this will cause a fatal error if $b is an empty array or not traversable e.g. not an array
in PHP 7.3 a warning will be raised if $b is not traversable
Why not use
$appended = array_merge($a,$b);
Why don't you want to use this, the correct, built-in method.
It's a pretty old post, but I want to add something about appending one array to another:
If
one or both arrays have associative keys
the keys of both arrays don't matter
you can use array functions like this:
array_merge(array_values($array), array_values($appendArray));
array_merge doesn't merge numeric keys so it appends all values of $appendArray. While using native php functions instead of a foreach-loop, it should be faster on arrays with a lot of elements.
Addition 2019-12-13:
Since PHP 7.4, there is the possibility to append or prepend arrays the Array Spread Operator way:
$a = [3, 4];
$b = [1, 2, ...$a];
As before, keys can be an issue with this new feature:
$a = ['a' => 3, 'b' => 4];
$b = ['c' => 1, 'a' => 2, ...$a];
"Fatal error: Uncaught Error: Cannot unpack array with string keys"
$a = [3 => 3, 4 => 4];
$b = [1 => 1, 4 => 2, ...$a];
array(4) {
[1]=>
int(1)
[4]=>
int(2)
[5]=>
int(3)
[6]=>
int(4)
}
$a = [1 => 1, 2 => 2];
$b = [...$a, 3 => 3, 1 => 4];
array(3) {
[0]=>
int(1)
[1]=>
int(4)
[3]=>
int(3)
}
<?php
// Example 1 [Merging associative arrays. When two or more arrays have same key
// then the last array key value overrides the others one]
$array1 = array("a" => "JAVA", "b" => "ASP");
$array2 = array("c" => "C", "b" => "PHP");
echo " <br> Example 1 Output: <br>";
print_r(array_merge($array1,$array2));
// Example 2 [When you want to merge arrays having integer keys and
//want to reset integer keys to start from 0 then use array_merge() function]
$array3 =array(5 => "CSS",6 => "CSS3");
$array4 =array(8 => "JAVASCRIPT",9 => "HTML");
echo " <br> Example 2 Output: <br>";
print_r(array_merge($array3,$array4));
// Example 3 [When you want to merge arrays having integer keys and
// want to retain integer keys as it is then use PLUS (+) operator to merge arrays]
$array5 =array(5 => "CSS",6 => "CSS3");
$array6 =array(8 => "JAVASCRIPT",9 => "HTML");
echo " <br> Example 3 Output: <br>";
print_r($array5+$array6);
// Example 4 [When single array pass to array_merge having integer keys
// then the array return by array_merge have integer keys starting from 0]
$array7 =array(3 => "CSS",4 => "CSS3");
echo " <br> Example 4 Output: <br>";
print_r(array_merge($array7));
?>
Output:
Example 1 Output:
Array
(
[a] => JAVA
[b] => PHP
[c] => C
)
Example 2 Output:
Array
(
[0] => CSS
[1] => CSS3
[2] => JAVASCRIPT
[3] => HTML
)
Example 3 Output:
Array
(
[5] => CSS
[6] => CSS3
[8] => JAVASCRIPT
[9] => HTML
)
Example 4 Output:
Array
(
[0] => CSS
[1] => CSS3
)
Reference Source Code
Following on from answer's by bstoney and Snark I did some tests on the various methods:
// Test 1 (array_merge)
$array1 = $array2 = array_fill(0, 50000, 'aa');
$start = microtime(true);
$array1 = array_merge($array1, $array2);
printf("Test 1: %.06f\n", microtime(true) - $start);
// Test2 (foreach)
$array1 = $array2 = array_fill(0, 50000, 'aa');
$start = microtime(true);
foreach ($array2 as $v) {
$array1[] = $v;
}
printf("Test 2: %.06f\n", microtime(true) - $start);
// Test 3 (... token)
// PHP 5.6+ and produces error if $array2 is empty
$array1 = $array2 = array_fill(0, 50000, 'aa');
$start = microtime(true);
array_push($array1, ...$array2);
printf("Test 3: %.06f\n", microtime(true) - $start);
Which produces:
Test 1: 0.002717
Test 2: 0.006922
Test 3: 0.004744
ORIGINAL: I believe as of PHP 7, method 3 is a significantly better alternative due to the way foreach loops now act, which is to make a copy of the array being iterated over.
Whilst method 3 isn't strictly an answer to the criteria of 'not array_push' in the question, it is one line and the most high performance in all respects, I think the question was asked before the ... syntax was an option.
UPDATE 25/03/2020:
I've updated the test which was flawed as the variables weren't reset. Interestingly (or confusingly) the results now show as test 1 being the fastest, where it was the slowest, having gone from 0.008392 to 0.002717! This can only be down to PHP updates, as this wouldn't have been affected by the testing flaw.
So, the saga continues, I will start using array_merge from now on!
For big array, is better to concatenate without array_merge, for avoid a memory copy.
$array1 = array_fill(0,50000,'aa');
$array2 = array_fill(0,100,'bb');
// Test 1 (array_merge)
$start = microtime(true);
$r1 = array_merge($array1, $array2);
echo sprintf("Test 1: %.06f\n", microtime(true) - $start);
// Test2 (avoid copy)
$start = microtime(true);
foreach ($array2 as $v) {
$array1[] = $v;
}
echo sprintf("Test 2: %.06f\n", microtime(true) - $start);
// Test 1: 0.004963
// Test 2: 0.000038
Since PHP 7.4 you can use the ... operator. This is also known as the splat operator in other languages, including Ruby.
$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
var_dump($fruits);
Output
array(5) {
[0]=>
string(6) "banana"
[1]=>
string(6) "orange"
[2]=>
string(5) "apple"
[3]=>
string(4) "pear"
[4]=>
string(10) "watermelon"
}
Splat operator should have better performance than array_merge. That’s not only because the splat operator is a language structure while array_merge is a function, but also because compile time optimization can be performant for constant arrays.
Moreover, we can use the splat operator syntax everywhere in the array, as normal elements can be added before or after the splat operator.
$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$arr3 = [...$arr1, ...$arr2];
$arr4 = [...$arr1, ...$arr3, 7, 8, 9];
Before PHP7 you can use:
array_splice($a, count($a), 0, $b);
array_splice() operates with reference to array (1st argument) and puts array (4th argument) values in place of list of values started from 2nd argument and number of 3rd argument. When we set 2nd argument as end of source array and 3rd as zero we append 4th argument values to 1st argument
if you want to merge empty array with existing new value. You must initialize it first.
$products = array();
//just example
for($brand_id=1;$brand_id<=3;$brand_id++){
array_merge($products,getByBrand($brand_id));
}
// it will create empty array
print_r($a);
//check if array of products is empty
for($brand_id=1;$brand_id<=3;$brand_id++){
if(empty($products)){
$products = getByBrand($brand_id);
}else{
array_merge($products,getByBrand($brand_id));
}
}
// it will create array of products
Hope its help.
foreach loop is faster than array_merge to append values to an existing array, so choose the loop instead if you want to add an array to the end of another.
// Create an array of arrays
$chars = [];
for ($i = 0; $i < 15000; $i++) {
$chars[] = array_fill(0, 10, 'a');
}
// test array_merge
$new = [];
$start = microtime(TRUE);
foreach ($chars as $splitArray) {
$new = array_merge($new, $splitArray);
}
echo microtime(true) - $start; // => 14.61776 sec
// test foreach
$new = [];
$start = microtime(TRUE);
foreach ($chars as $splitArray) {
foreach ($splitArray as $value) {
$new[] = $value;
}
}
echo microtime(true) - $start; // => 0.00900101 sec
// ==> 1600 times faster

Can't concatenate 2 arrays in PHP

I've recently learned how to join 2 arrays using the + operator in PHP.
But consider this code...
$array = array('Item 1');
$array += array('Item 2');
var_dump($array);
Output is
array(1) { [0]=> string(6) "Item
1" }
Why does this not work? Skipping the shorthand and using $array = $array + array('Item 2') does not work either. Does it have something to do with the keys?
Both will have a key of 0, and that method of combining the arrays will collapse duplicates. Try using array_merge() instead.
$arr1 = array('foo'); // Same as array(0 => 'foo')
$arr2 = array('bar'); // Same as array(0 => 'bar')
// Will contain array('foo', 'bar');
$combined = array_merge($arr1, $arr2);
If the elements in your array used different keys, the + operator would be more appropriate.
$arr1 = array('one' => 'foo');
$arr2 = array('two' => 'bar');
// Will contain array('one' => 'foo', 'two' => 'bar');
$combined = $arr1 + $arr2;
Edit: Added a code snippet to clarify
Use array_merge()
See the documentation here:
http://php.net/manual/en/function.array-merge.php
Merges the elements of one or more arrays together so that the values of one are appended to the end of the previous one. It returns the resulting array.
IMO some of the previous answers are incorrect!
(It's possible to sort the answers to start from oldest to newest).
array_merge() actually merges the arrays, meaning, if the arrays have a common item one of the copies will be omitted. Same goes for + (union).
I didn't find a "work-around" for this issue, but to do it manually...
Here it goes:
<?php
$part1 = array(1,2,3);
echo "array 1 = \n";
print_r($part1);
$part2 = array(4,5,6);
echo "array 2 = \n";
print_r($part2);
$ans = NULL;
for ($i = 0; $i < count($part1); $i++) {
$ans[] = $part1[$i];
}
for ($i = 0; $i < count($part2); $i++) {
$ans[] = $part2[$i];
}
echo "after arrays concatenation:\n";
print_r($ans);
?>
use the splat ( or spread ) operator:
$animals = ['dog', 'cat', 'snake', 'pig', 'chicken'];
$fruits = ['apple', 'banana', 'water melon'];
$things = [...$animals, ...$fruits];
source: https://www.kindacode.com/article/merging-arrays-in-php-7/
+ is called the Union operator, which differs from a Concatenation operator (PHP doesn't have one for arrays). The description clearly says:
The + operator appends elements of remaining keys from the right handed array to the left handed, whereas duplicated keys are NOT overwritten.
With the example:
$a = array("a" => "apple", "b" => "banana");
$b = array("a" => "pear", "b" => "strawberry", "c" => "cherry");
$c = $a + $b;
array(3) {
["a"]=>
string(5) "apple"
["b"]=>
string(6) "banana"
["c"]=>
string(6) "cherry"
}
Since both your arrays have one entry with the key 0, the result is expected.
To concatenate, use array_merge.
Try array_merge.
$array1 = array('Item 1');
$array2 = array('Item 2');
$array3 = array_merge($array1, $array2);
I think its because you are not assigning a key to either, so they both have key of 0, and the + does not re-index, so its trying to over write it.
It is indeed a key conflict. When concatenating arrays, duplicate keys are not overwritten.
Instead you must use array_merge()
$array = array_merge(array('Item 1'), array('Item 2'));
$array = array('Item 1');
array_push($array,'Item 2');
or
$array[] = 'Item 2';
This works for non-associative arrays:
while(($item = array_shift($array2)) !== null && array_push($array1, $item));
Try saying
$array[] = array('Item 2');
Although it looks like you're trying to add an array into an array, thus $array[][] but that's not what your title suggests.
you may use operator .
$array3 = $array1.$array2;

Categories