I have an array with 4 values. I would like to remove the value at the 2nd position and then have the rest of the key's shift down one.
$b = array(123,456,789,123);
Before Removing the Key at the 2nd position:
Array ( [0] => 123 [1] => 456 [2] => 789 [3] => 123 )
After I would like the remaining keys to shift down one to fill in the space of the missing key
Array ( [0] => 123 [1] => 789 [2] => 123 )
I tried using unset() on the specific key, but it would not shift down the remaining keys. How do I remove a specific key in an array using php?
You need array_values($b) in order to re-key the array so the keys are sequential and numeric (starting at 0).
The following should do the trick:
$b = array(123,456,789,123);
unset($b[1]);
$b = array_values($b);
echo "<pre>"; print_r($b);
It is represented that your input data is an indexed array (there are no gaps in the sequence of the integer keys which start from zero). I'll compare the obvious techniques that directly deliver the desired result from the OP's sample data.
1. unset() then array_values()
unset($b[1]);
$b = array_value($b);
This is safe to use without checking for the existence of the index -- if missing, there will be no error.
unset() can receive multiple parameters, so if more elements need to be removed, then the number of function calls remains the same. e.g. unset($b[1], $b[3], $b[5]);
unset() cannot be nested inside of array_values() to form a one-liner because unset() modifies the variable and returns no value.
AFAIK, unset() is not particularly handy for removing elements using a dynamic whitelist/blacklist of keys.
2. array_splice()
array_splice($b, 1, 1);
// (input array, starting position, number of elements to remove)
This function is key-ignorant, it will target elements based on their position in the array. This is safe to use without checking for the existence of the position -- if missing, there will be no error.
array_splice() can remove a single element or, at best, remove multiple consecutive elements. If you need to remove non-consecutive elements you would need to make additional function calls.
array_splice() does not require an array_values() call because "Numerical keys in input are not preserved" -- this may or may not be desirable in certain situations.
3. array_filter() nested in array_values()
array_values(
array_filter(
$b,
function($k) {
return $k != 1;
},
ARRAY_FILTER_USE_KEY
)
)
This technique relies on a custom function call and a flag to tell the filter to iterate only the keys.
It will be a relatively poor performer because it will iterate all of the elements regardless of the logical necessity.
It is the most verbose of the options that I will discuss.
It further loses efficiency if you want to employ an in_array() call with a whitelist/blacklist of keys in the custom function.
Prior to PHP7.4, passing a whitelist/blacklist/variable into the custom function scope will require the use of use().
It can be written as a one-liner.
This is safe to use without checking for the existence of the index(es) -- if missing, there will be no error.
4. array_diff_key() nested in array_values()
array_values(
array_diff_key(
$b,
[1 => '']
)
);
This technique isn't terribly verbose, but it is a bit of an overkill if you only need to remove one element.
array_diff_key() really shines when there is a whitelist/blacklist array of keys (which may have a varying element count). PHP is very swift at processing keys, so this function is very efficient at the task that it was designed to do.
The values in the array which is declared as the second parameter of array_diff_key() are completely irrelevant -- they can be null or 999 or 'eleventeen' -- only the keys are respected.
array_diff_key() does not have any scoping challenges, compared to array_filter(), because there is no custom function called.
It can be written as a one-liner.
This is safe to use without checking for the existence of the index(es) -- if missing, there will be no error.
Use array_splice().
array_splice( $b, 1, 1 );
// $b == Array ( [0] => 123 [1] => 789 [2] => 123 )
No one has mentioned this, so i will do: sort() is your friend.
$fruits = array("lemon", "orange", "banana", "apple");
sort($fruits);
foreach($fruits as $key => $val)
echo "fruits[$key] = $val";
output:
fruits[0] = apple
fruits[1] = banana
fruits[2] = lemon
fruits[3] = orange
// remove Lemon, too bitter
unset($fruits[2]);
// keep keys with asort
asort($fruits);
foreach($fruits as $key => $val)
echo "fruits[$key] = $val";
Output:
fruits[0] = apple
fruits[1] = banana
fruits[3] = orange
This is the one you want to use to reindex the keys:
// reindex keys with sort
sort($fruits);
foreach($fruits as $key => $val)
echo "fruits[$key] = $val";
Output:
fruits[0] = apple
fruits[1] = banana
fruits[2] = orange
If you want to remove an item from an array at a specific position, you can obtain the key for that position and then unset it:
$b = array(123,456,789,123);
$p = 2;
$a = array_keys($b);
if ($p < 0 || $p >= count($a))
{
throw new RuntimeException(sprintf('Position %d does not exists.', $p));
}
$k = $a[$p-1];
unset($b[$k]);
This works with any PHP array, regardless where the indexing starts or if strings are used for keys.
If you want to renumber the remaining array just use array_values:
$b = array_values($b);
Which will give you a zero-based, numerically indexed array.
If the original array is a zero-based, numerically indexed array as well (as in your question), you can skip the part about obtaining the key:
$b = array(123,456,789,123);
$p = 2;
if ($p < 0 || $p >= count($b))
{
throw new RuntimeException(sprintf('Position %d does not exists.', $p));
}
unset($b[$p-1]);
$b = array_values($b);
Or directly use array_splice which deals with offsets instead of keys and re-indexes the array (numeric keys in input are not preserved):
$b = array(123,456,789,123);
$p = 2;
if ($p < 0 || $p >= count($b))
{
throw new RuntimeException(sprintf('Position %d does not exists.', $p));
}
array_splice($b, $p-1, 1);
Related
I have a multidimensional array in PHP where I need to remove one array based on the value of an item in one of the arrays:
Example Array
array(
"0"=>array("0"=>"joe", "1"=>"2018-07-18 09:00:00"),
"1"=>array("0"=>"tom", "1"=>"2018-07-17 09:00:00"),
"2"=>array("0"=>"joe", "1"=>"2018-07-14 09:00:00")
)
I know that I want to remove the array that contains joe in key 0, but I only want to remove the array that contains joe with the most current date in key1. The following output is what I'm trying to accomplish:
array(
"0"=>array("0"=>"tom", "1"=>"2018-07-17 09:00:00"),
"1"=>array("0"=>"joe", "1"=>"2018-07-14 09:00:00")
)
Is there a simple way to do this in PHP aside from looping through each array?
Here is a non looping method that uses array_intersect and array_column to find the "Joe's" and then deletes the maximum array_key since I first sort the array on dates.
usort($arr, function($a, $b) {
return $a[1] <=> $b[1];
}); // This returns the array sorted by date
// Array_column grabs all the names in the array to a single array.
// Array_intersect matches it to the name "Joe" and returns the names and keys of "Joe"
$joes = array_intersect(array_column($arr, 0), ["joe"]);
// Array_keys grabs the keys from the array as values
// Max finds the maximum value (key)
$current = max(array_keys($joes));
unset($arr[$current]);
var_dump($arr);
https://3v4l.org/mah6K
Edit forgot to add the array_values() if you want to reset the keys in the array.
Just add $arr = array_values($arr); after the unset.
I would go about it like this:
<?php
$foo = array(
"0"=>array("0"=>"joe", "1"=>"2018-07-18 09:00:00"),
"1"=>array("0"=>"tom", "1"=>"2018-07-17 09:00:00"),
"2"=>array("0"=>"joe", "1"=>"2018-07-14 09:00:00")
);
$tmp = [];
foreach($foo as $k => $v) {
if ($v[0] === 'joe') {
$tmp[$v[1]] = $k;
}
}
if (!empty($tmp)) {
sort($tmp); //think that is sane with date format?
unset($foo[reset($tmp)]);
}
var_dump($foo);
Not sure if you don't want to loop on principal or what... I tend to go for readability. Find all occurrences of joe. Sort on date. Remove the most recent by key.
I know that if you manually declare the keys in your array, it is considered hash and if it is a self-generated key, it is an array(sequential). So what if I manually declare
$array1 = array(1 => 123, 2 => 312, 3 => 456);
// and
$array2 = array(123,312,456);
Questions:
Is $array1 an array or hash?
Is my idea on hash and array correct?
PHP uses only associative arrays. To determine if an array could be an indexed array from 0 to size - 1 eg an array where elements have been pushed, or added using array[] = x, the only method known is to check if all keys are from 0 to size - 1.
(Note that an array could be built via the "associative" way (ie providing both keys and values), using incremental keys from 0, and there is no way to determine that it was not built using the method given above (push or []), since, anyway, that makes no difference)
$i = 0;
foreach (array_keys($array) as $key) {
if ($key !== $i) break; // Note the !== (not !=)
$i++;
}
if ($i == count($array)) {
// looks like array was built using indexing (see text above)
}
The final test $i == count($array), if true, indicates that all keys where numeric, starting from 0, incremented by 1 for each element, until the last element.
How can I delete duplicates in array?
For example if I had the following array:
$array = array('1','1','2','3');
I want it to become
$array = array('2','3');
so I want it to delete the whole value if two of it are found
Depending on PHP version, this should work in all versions of PHP >= 4.0.6 as it doesn't require anonymous functions that require PHP >= 5.3:
function moreThanOne($val) {
return $val < 2;
}
$a1 = array('1','1','2','3');
print_r(array_keys(array_filter(array_count_values($a1), 'moreThanOne')));
DEMO (Change the PHP version in the drop-down to select the version of PHP you are using)
This works because:
array_count_values will go through the array and create an index for each value and increment it each time it encounters it again.
array_filter will take the created array and pass it through the moreThanOne function defined earlier, if it returns false, the key/value pair will be removed.
array_keys will discard the value portion of the array creating an array with the values being the keys that were defined. This final step gives you a result that removes all values that existed more than once within the original array.
You can filter them out using array_count_values():
$array = array('1','1','2','3');
$res = array_keys(array_filter(array_count_values($array), function($freq) {
return $freq == 1;
}));
The function returns an array comprising the original values and their respective frequencies; you then pick only the single frequencies. The end result is obtained by retrieving the keys.
Demo
Try this code,
<?php
$array = array('1','1','2','3');
foreach($array as $data){
$key= array_keys($array,$data);
if(count($key)>1){
foreach($key as $key2 => $data2){
unset($array[$key2]);
}
}
}
$array=array_values($array);
print_r($array);
?>
Output
Array ( [0] => 2 [1] => 3 )
PHP offers so many array functions, you just have to combine them:
$arr = array_keys(array_filter(array_count_values($arr), function($val) {
return $val === 1;
}));
Reference: array_keys, array_filter, array_count_values
DEMO
Remove duplicate values from an array.
array_unique($array)
$array = array(4, "4", "3", 4, 3, "3");
$result = array_unique($array);
print_r($result);
/*
Array
(
[0] => 4
[2] => 3
)
*/
In my code I need to make a number of copies of a dummy array. The array is simple, for example $dummy = array('val'=> 0). I would like make N copies of this array and tack them on to the end of an existing array that has a similar structure. Obviously this could be done with a for loop but for readability, I'm wondering if there are any built in functions that would make this more verbose.
Here's the code I came up with using a for loop:
//example data, not real code
$existingArray = array([0] => array('val'=>2),[1] => array('val'=>3) );
$n = 2;
for($i=0;$i<$n;$i++) {
$dummy = array('val'=>0); //make a new array
$existingArray[] = $dummy; //add it to the end of $existingArray
}
To reiterate, I'd like to rewrite this with functions if such functions exist. Something along the lines of this (obviously these are not real functions):
//make $n copies of the array
$newvals = clone(array('val'=>0), $n);
//tack the new arrays on the end of the existing array
append($newvals, $existingArray)
I think you're looking for array_fill:
array array_fill ( int $start_index , int $num , mixed $value )
Fills an array with num entries of the value of the value parameter, keys starting at the start_index parameter.
So:
$newElements = array_fill(0, $n, Array('val' => 0));
You do still have to handle the appending of $newElements to $existingArray yourself, probably with array_merge:
array array_merge ( array $array1 [, array $... ] )
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.
If the input arrays have the same string keys, then the later value for that key will overwrite the previous one. If, however, the arrays contain numeric keys, the later value will not overwrite the original value, but will be appended.
Values in the input array with numeric keys will be renumbered with incrementing keys starting from zero in the result array.
So:
$existingArray = array_merge($existingArray, $newElements);
This all works because your top-level arrays are numerically-indexed.
Having a brain freeze over a fairly trivial problem. If I start with an array like this:
$my_array = array(
'monkey' => array(...),
'giraffe' => array(...),
'lion' => array(...)
);
...and new elements might get added with different keys but always an array value. Now I can be sure the first element is always going to have the key 'monkey' but I can't be sure of any of the other keys.
When I've finished filling the array I want to move the known element 'monkey' to the end of the array without disturbing the order of the other elements. What is the most efficient way to do this?
Every way I can think of seems a bit clunky and I feel like I'm missing something obvious.
The only way I can think to do this is to remove it then add it:
$v = $my_array['monkey'];
unset($my_array['monkey']);
$my_array['monkey'] = $v;
array_shift is probably less efficient than unsetting the index, but it works:
$my_array = array('monkey' => 1, 'giraffe' => 2, 'lion' => 3);
$my_array['monkey'] = array_shift($my_array);
print_r($my_array);
Another alternative is with a callback and uksort:
uksort($my_array, create_function('$x,$y','return ($y === "monkey") ? -1 : 1;'));
You will want to use a proper lambda if you are using PHP5.3+ or just define the function as a global function regularly.
I really like #Gordon's answer for its elegance as a one liner, but it only works if the targeted key exists in the first element of the array. Here's another one-liner that will work for a key in any position:
$arr = ['monkey' => 1, 'giraffe' => 2, 'lion' => 3];
$arr += array_splice($arr, array_search('giraffe', array_keys($arr)), 1);
Demo
Beware, this fails with numeric keys because of the way that the array union operator (+=) works with numeric keys (Demo).
Also, this snippet assumes that the targeted key is guaranteed to exist in the array. If the targeted key does not exist, then the result will incorrectly move the first element to the end because array_search() will return false which will be coalesced to 0 by array_splice() (Demo).
You can implement some basic calculus and get a universal function for moving array element from one position to the other.
For PHP it looks like this:
function magicFunction ($targetArray, $indexFrom, $indexTo) {
$targetElement = $targetArray[$indexFrom];
$magicIncrement = ($indexTo - $indexFrom) / abs ($indexTo - $indexFrom);
for ($Element = $indexFrom; $Element != $indexTo; $Element += $magicIncrement){
$targetArray[$Element] = $targetArray[$Element + $magicIncrement];
}
$targetArray[$indexTo] = $targetElement;
}
Check out "moving array elements" at "gloommatter" for detailed explanation.
http://www.gloommatter.com/DDesign/programming/moving-any-array-elements-universal-function.html