if I give you an array:
$a = array('something' => 'value', 'apple' => 'sauce');
and said given the key, find the position and insert something before it - what would you do?
I can find something by doing:
function insert($value, $array)
foreach($array as $k=>$v) {
if ($k === $value) {
// I am stuck here ...
}
}
}
But I don't know how to insert before $k in the array. This example assumes the array always has key=>value.
Update 1
Apologies all, I don't think I was very clear. Given the above information the goal is to use this "insert" function to insert a new key=>value, so given the above sample array, I want to do:
insert(array('new_key' => 'new_value'), 'something', $a)
So the above for loop would have to be changed to:
function insert($array, $key, $originalArray)
foreach($originalArray as $k=>$v) {
if ($k === $key) {
// Insert $array right before 'something'
// I am stuck here ...
}
}
}
The result would be a new array that looks like:
$a = array('new_key' => 'new_value', 'something' => 'value', 'apple' => 'sauce');
The goal is to find the key in the given array and insert the new array right before it. Both arrays must be key/value.
Here is a function which will insert an element into an array before or after the chosen value. It returns the modified array.
function associativeArrayInject($originalArray, $targetKey, $newKey, $newValue, $insertBefore=true){
# We will build a new array from the ground up, and return it. This is that array.
$newArray = array();
# Loop over the original array.
foreach($originalArray as $key => $value){
# If we need to inject the data before the current key, we
# do that here
if($key === $targetKey && $insertBefore)
$newArray[$newKey] = $newValue;
# At this point, we insert the $originalArray's key and value
# because if we needed to inject before, it's already been done,
# and if we need to inject after, we'll do that next
$newArray[$key] = $value;
# If we need to inject the data after the current key, we
# do that here
if($key === $targetKey && !$insertBefore)
$newArray[$newKey] = $newValue;
}
# When all the array values are looped over, the new array will have
# been constructed with the new data in the appropriate spot. Now
# we can return it.
return $newArray;
}
Sol. 1: Try to use arsort() or similar functions of sorting arrays in php.
Sol. 2: At first init array of values and than use foreach loop to sort array how you like.
Sol. 3: You can create multidimensional array, something like this:
$array[$position]['something']['value'];
And than use ksort function to sort array by keys. So, this is my idea.
Also, show exactly how you wana sort array. ( like input ( some data ) => output ( some data ) )
Several variations whether you want to modify in place with a reference or return the new array:
function insert(&$array, $search, $value) {
$i = 0;
foreach($array as $k => $v) {
if ($k === $search) {
return array_splice($array, $i+1, 0, $value);
}
$i++;
}
}
$a = array('foo' => 'bar', 'something' => 'value', 'apple' => 'sauce');
insert($a, 'something', 'new value');
Related
I can't seem to find a simple, straight-forward solution to the age-old problem of removing empty elements from arrays in PHP.
My input array may look like this:
Array ( [0] => Array ( [Name] => [EmailAddress] => ) )
(And so on, if there's more data, although there may not be...)
If it looks like the above, I want it to be completely empty after I've processed it.
So print_r($array); would output:
Array ( )
If I run $arrayX = array_filter($arrayX); I still get the same print_r output. Everywhere I've looked suggests this is the simplest way of removing empty array elements in PHP5, however.
I also tried $arrayX = array_filter($arrayX,'empty_array'); but I got the following error:
Warning: array_filter() [function.array-filter]: The second argument, 'empty_array', should be a valid callback
What am I doing wrong?
Try using array_map() to apply the filter to every array in $array:
$array = array_map('array_filter', $array);
$array = array_filter($array);
Demo: http://codepad.org/xfXEeApj
There are numerous examples of how to do this. You can try the docs, for one (see the first comment).
function array_filter_recursive($array, $callback = null) {
foreach ($array as $key => & $value) {
if (is_array($value)) {
$value = array_filter_recursive($value, $callback);
}
else {
if ( ! is_null($callback)) {
if ( ! $callback($value)) {
unset($array[$key]);
}
}
else {
if ( ! (bool) $value) {
unset($array[$key]);
}
}
}
}
unset($value);
return $array;
}
Granted this example doesn't actually use array_filter but you get the point.
The accepted answer does not do exactly what the OP asked. If you want to recursively remove ALL values that evaluate to false including empty arrays then use the following function:
function array_trim($input) {
return is_array($input) ? array_filter($input,
function (& $value) { return $value = array_trim($value); }
) : $input;
}
Or you could change the return condition according to your needs, for example:
{ return !is_array($value) or $value = array_trim($value); }
If you only want to remove empty arrays. Or you can change the condition to only test for "" or false or null, etc...
Following up jeremyharris' suggestion, this is how I needed to change it to make it work:
function array_filter_recursive($array) {
foreach ($array as $key => &$value) {
if (empty($value)) {
unset($array[$key]);
}
else {
if (is_array($value)) {
$value = array_filter_recursive($value);
if (empty($value)) {
unset($array[$key]);
}
}
}
}
return $array;
}
Try with:
$array = array_filter(array_map('array_filter', $array));
Example:
$array[0] = array(
'Name'=>'',
'EmailAddress'=>'',
);
print_r($array);
$array = array_filter(array_map('array_filter', $array));
print_r($array);
Output:
Array
(
[0] => Array
(
[Name] =>
[EmailAddress] =>
)
)
Array
(
)
array_filter() is not type-sensitive by default. This means that any zero-ish, false-y, null, empty values will be removed. My links to follow will demonstrate this point.
The OP's sample input array is 2-dimensional. If the data structure is static then recursion is not necessary. For anyone who would like to filter the zero-length values from a multi-dimensional array, I'll provide a static 2-dim method and a recursive method.
Static 2-dim Array:
This code performs a "zero-safe" filter on the 2nd level elements and then removes empty subarrays: (See this demo to see this method work with different (trickier) array data)
$array=[
['Name'=>'','EmailAddress'=>'']
];
var_export(
array_filter( // remove the 2nd level in the event that all subarray elements are removed
array_map( // access/iterate 2nd level values
function($v){
return array_filter($v,'strlen'); // filter out subarray elements with zero-length values
},$array // the input array
)
)
);
Here is the same code as a one-liner:
var_export(array_filter(array_map(function($v){return array_filter($v,'strlen');},$array)));
Output (as originally specified by the OP):
array (
)
*if you don't want to remove the empty subarrays, simply remove the outer array_filter() call.
Recursive method for multi-dimensional arrays of unknown depth: When the number of levels in an array are unknown, recursion is a logical technique. The following code will process each subarray, removing zero-length values and any empty subarrays as it goes. Here is a demo of this code with a few sample inputs.
$array=[
['Name'=>'','Array'=>['Keep'=>'Keep','Drop'=>['Drop2'=>'']],'EmailAddress'=>'','Pets'=>0,'Children'=>null],
['Name'=>'','EmailAddress'=>'','FavoriteNumber'=>'0']
];
function removeEmptyValuesAndSubarrays($array){
foreach($array as $k=>&$v){
if(is_array($v)){
$v=removeEmptyValuesAndSubarrays($v); // filter subarray and update array
if(!sizeof($v)){ // check array count
unset($array[$k]);
}
}elseif(!strlen($v)){ // this will handle (int) type values correctly
unset($array[$k]);
}
}
return $array;
}
var_export(removeEmptyValuesAndSubarrays($array));
Output:
array (
0 =>
array (
'Array' =>
array (
'Keep' => 'Keep',
),
'Pets' => 0,
),
1 =>
array (
'FavoriteNumber' => '0',
),
)
If anyone discovers an input array that breaks my recursive method, please post it (in its simplest form) as a comment and I'll update my answer.
When this question was asked, the latest version of PHP was 5.3.10. As of today, it is now 8.1.1, and a lot has changed since! Some of the earlier answers will provide unexpected results, due to changes in the core functionality. Therefore, I feel an up-to-date answer is required. The below will iterate through an array, remove any elements that are either an empty string, empty array, or null (so false and 0 will remain), and if this results in any more empty arrays, it will remove them too.
function removeEmptyArrayElements( $value ) {
if( is_array($value) ) {
$value = array_map('removeEmptyArrayElements', $value);
$value = array_filter( $value, function($v) {
// Change the below to determine which values get removed
return !( $v === "" || $v === null || (is_array($v) && empty($v)) );
} );
}
return $value;
}
To use it, you simply call removeEmptyArrayElements( $array );
If used inside class as helper method:
private function arrayFilterRecursive(array $array): array
{
foreach ($array as $key => &$value) {
if (empty($value)) {
unset($array[$key]);
} else if (is_array($value)) {
$value = self::arrayFilterRecursive($value);
}
}
return $array;
}
I have a two-dimensional array and look for a way to find the all double entries. E.g. if the array is of the form
$a = array(
array('a','b','c'),
array('d','a','e'),
array('d','c','b')
)
the function should return the list
array(array(0,0),array(1,1)) // Since $a[0,0]=$a[1,1]
array(array(0,1),array(2,2)) // Since $a[0,1]=$a[2,2]
array(array(0,2),array(2,1)) // Since $a[0,2]=$a[2,1]
array(array(1,0),array(2,0)) // Since $a[1,0]=$a[2,0]
array(1,2) // Unmatched
Is there an elegant/efficient way to implement this?
With a nested loop. Use the values as keys in the result and append the coordinates as arrays under those keys.
foreach ($a as $x => $inner) {
foreach ($inner as $y => $value) {
$result[$value][] = [$x, $y];
}
}
The $result will contain sets of coordinates for all the given values. You can group the results by size of set to identify which values are unmatched, pairs, or have even greater than two occurrences (if that's possible).
foreach ($result as $value => $set) {
$sets[count($set)][$value] = $set;
}
I can't seem to find a simple, straight-forward solution to the age-old problem of removing empty elements from arrays in PHP.
My input array may look like this:
Array ( [0] => Array ( [Name] => [EmailAddress] => ) )
(And so on, if there's more data, although there may not be...)
If it looks like the above, I want it to be completely empty after I've processed it.
So print_r($array); would output:
Array ( )
If I run $arrayX = array_filter($arrayX); I still get the same print_r output. Everywhere I've looked suggests this is the simplest way of removing empty array elements in PHP5, however.
I also tried $arrayX = array_filter($arrayX,'empty_array'); but I got the following error:
Warning: array_filter() [function.array-filter]: The second argument, 'empty_array', should be a valid callback
What am I doing wrong?
Try using array_map() to apply the filter to every array in $array:
$array = array_map('array_filter', $array);
$array = array_filter($array);
Demo: http://codepad.org/xfXEeApj
There are numerous examples of how to do this. You can try the docs, for one (see the first comment).
function array_filter_recursive($array, $callback = null) {
foreach ($array as $key => & $value) {
if (is_array($value)) {
$value = array_filter_recursive($value, $callback);
}
else {
if ( ! is_null($callback)) {
if ( ! $callback($value)) {
unset($array[$key]);
}
}
else {
if ( ! (bool) $value) {
unset($array[$key]);
}
}
}
}
unset($value);
return $array;
}
Granted this example doesn't actually use array_filter but you get the point.
The accepted answer does not do exactly what the OP asked. If you want to recursively remove ALL values that evaluate to false including empty arrays then use the following function:
function array_trim($input) {
return is_array($input) ? array_filter($input,
function (& $value) { return $value = array_trim($value); }
) : $input;
}
Or you could change the return condition according to your needs, for example:
{ return !is_array($value) or $value = array_trim($value); }
If you only want to remove empty arrays. Or you can change the condition to only test for "" or false or null, etc...
Following up jeremyharris' suggestion, this is how I needed to change it to make it work:
function array_filter_recursive($array) {
foreach ($array as $key => &$value) {
if (empty($value)) {
unset($array[$key]);
}
else {
if (is_array($value)) {
$value = array_filter_recursive($value);
if (empty($value)) {
unset($array[$key]);
}
}
}
}
return $array;
}
Try with:
$array = array_filter(array_map('array_filter', $array));
Example:
$array[0] = array(
'Name'=>'',
'EmailAddress'=>'',
);
print_r($array);
$array = array_filter(array_map('array_filter', $array));
print_r($array);
Output:
Array
(
[0] => Array
(
[Name] =>
[EmailAddress] =>
)
)
Array
(
)
array_filter() is not type-sensitive by default. This means that any zero-ish, false-y, null, empty values will be removed. My links to follow will demonstrate this point.
The OP's sample input array is 2-dimensional. If the data structure is static then recursion is not necessary. For anyone who would like to filter the zero-length values from a multi-dimensional array, I'll provide a static 2-dim method and a recursive method.
Static 2-dim Array:
This code performs a "zero-safe" filter on the 2nd level elements and then removes empty subarrays: (See this demo to see this method work with different (trickier) array data)
$array=[
['Name'=>'','EmailAddress'=>'']
];
var_export(
array_filter( // remove the 2nd level in the event that all subarray elements are removed
array_map( // access/iterate 2nd level values
function($v){
return array_filter($v,'strlen'); // filter out subarray elements with zero-length values
},$array // the input array
)
)
);
Here is the same code as a one-liner:
var_export(array_filter(array_map(function($v){return array_filter($v,'strlen');},$array)));
Output (as originally specified by the OP):
array (
)
*if you don't want to remove the empty subarrays, simply remove the outer array_filter() call.
Recursive method for multi-dimensional arrays of unknown depth: When the number of levels in an array are unknown, recursion is a logical technique. The following code will process each subarray, removing zero-length values and any empty subarrays as it goes. Here is a demo of this code with a few sample inputs.
$array=[
['Name'=>'','Array'=>['Keep'=>'Keep','Drop'=>['Drop2'=>'']],'EmailAddress'=>'','Pets'=>0,'Children'=>null],
['Name'=>'','EmailAddress'=>'','FavoriteNumber'=>'0']
];
function removeEmptyValuesAndSubarrays($array){
foreach($array as $k=>&$v){
if(is_array($v)){
$v=removeEmptyValuesAndSubarrays($v); // filter subarray and update array
if(!sizeof($v)){ // check array count
unset($array[$k]);
}
}elseif(!strlen($v)){ // this will handle (int) type values correctly
unset($array[$k]);
}
}
return $array;
}
var_export(removeEmptyValuesAndSubarrays($array));
Output:
array (
0 =>
array (
'Array' =>
array (
'Keep' => 'Keep',
),
'Pets' => 0,
),
1 =>
array (
'FavoriteNumber' => '0',
),
)
If anyone discovers an input array that breaks my recursive method, please post it (in its simplest form) as a comment and I'll update my answer.
When this question was asked, the latest version of PHP was 5.3.10. As of today, it is now 8.1.1, and a lot has changed since! Some of the earlier answers will provide unexpected results, due to changes in the core functionality. Therefore, I feel an up-to-date answer is required. The below will iterate through an array, remove any elements that are either an empty string, empty array, or null (so false and 0 will remain), and if this results in any more empty arrays, it will remove them too.
function removeEmptyArrayElements( $value ) {
if( is_array($value) ) {
$value = array_map('removeEmptyArrayElements', $value);
$value = array_filter( $value, function($v) {
// Change the below to determine which values get removed
return !( $v === "" || $v === null || (is_array($v) && empty($v)) );
} );
}
return $value;
}
To use it, you simply call removeEmptyArrayElements( $array );
If used inside class as helper method:
private function arrayFilterRecursive(array $array): array
{
foreach ($array as $key => &$value) {
if (empty($value)) {
unset($array[$key]);
} else if (is_array($value)) {
$value = self::arrayFilterRecursive($value);
}
}
return $array;
}
Do I really have to do this to reset an array?
foreach ($array as $i => $value) {
unset($array[$i]);
}
EDIT:
This one makes more sense, as the previous one is equivalent to $array=array();
foreach ($array as $i => $value) {
$array[$i]=NULL;
}
$keys = array_keys($array);
$values = array_fill(0, count($keys), null);
$new_array = array_combine($keys, $values);
Get the Keys
Get an array of nulls with the same number of elements
Combine them, using keys and the keys, and the nulls as the values
As comments suggest, this is easy as of PHP 5.2 with array_fill_keys
$new_array = array_fill_keys(array_keys($array), null);
Fill array with old keys and null values
$array = array_fill_keys(array_keys($array), null)
There is no build-in function to reset an array to just it's keys.
An alternative would be via a callback and array_map():
$array = array( 'a' => 'foo', 'b' => 'bar', 'c' => 'baz' );
With regular callback function
function nullify() {}
$array = array_map('nullify', $array);
Or with a lambda with PHP < 5.3
$array = array_map(create_function('', ''), $array);
Or with lambda as of PHP 5.3
$array = array_map(function() {}, $array);
In all cases var_dump($array); outputs:
array(3) {
["a"]=> NULL
["b"]=> NULL
["c"]=> NULL
}
Define this function and call it whenever you need it:
function erase_val(&$myarr) {
$myarr = array_map(create_function('$n', 'return null;'), $myarr);
}
// It's call by reference so you don't need to assign your array to a variable.
// Just call the function upon it
erase_val($array);
That's all!
Get the array keys, then use them to create a new array with NULL values:
array_fill_keys(array_keys($array), NULL);
About array_fill_keys():
The array_fill_keys() function fills an array with values, specifying keys.
About array_keys():
The array_keys() function returns all the keys of an array.
foreach($a as &$v)
$v = null;
The reasoning behind setting an array item to null is that an array needs to have a value for each key, otherwise a key makes no sense. That is why it is called a key - it is used to access a value. A null value seems like a reasonable choice here.
Wrap it in a [reusable] procedure:
function array_purge_values(&$a) {
foreach($a as &$v)
$v = null;
}
Keep in mind though that PHP versions 5.3 and those released later, pass values to functions by reference by default, i.e. the ampersand preceding argument variable in the function declaration is redundant. Not only that, but you will get a warning that the notion is deprecated.
If you need to nullify the values of a associative array you can walk the whole array and make a callback to set values to null thus still having keys
array_walk($ar,function(&$item){$item = null;});
In case if you need to nullify the whole array just reassign it to empty one
$ar = array();
unset would delete the key, You need to set the value to null or 0 as per your requirement.
Example
I don't get the question quite well, but your example
foreach ($array as $i => $value) {
unset($array[$i]);
}
is equivilent to
$array = array();
Why not making an array with required keys and asinging it to variable when you want reset it?
function resetMyArr(&$arr)
{
$arr = array('key1'=>null,'key2'=>null);
}
This is a fairly old topic, but since I referenced to it before coming up with my own solution for a more specific result, so therefore I will share with you that solution.
The desired result was to nullify all values, while keeping keys, and for it to recursively search the array for sub-arrays as well.
RECURSIVELY SET MULTI-LEVEL ARRAY VALUES TO NULL:
function nullifyArray(&$arrayData) {
if (is_array($arrayData)) {
foreach ($arrayData as $aKey => &$aValue) {
if (is_array($aValue)) {
nullifyArray($aValue);
} else {
$aValue = null;
}
}
return true; // $arrayData IS an array, and has been processed.
} else {
return false; // $arrayData is NOT an array, no action(s) were performed.
}
}
And here is it in use, along with BEFORE and AFTER output of the array contents.
PHP code to create a multilevel-array, and call the nullifyArray() function:
// Create a multi-level array.
$testArray = array(
'rootKey1' => 'rootValue1',
'rootKey2' => 'rootValue2',
'rootArray1' => array(
'subKey1' => 'subValue1',
'subArray1' => array(
'subSubKey1' => 'subSubValue1',
'subSubKey2' => 'subSubValue2'
)
)
);
// Nullify the values.
nullifyArray($testArray);
BEFORE CALL TO nullifyArray():
Array
(
[rootKey1] => rootValue1
[rootKey2] => rootValue2
[rootArray1] => Array
(
[subKey1] => subValue1
[subArray1] => Array
(
[subSubKey1] => subSubValue1
[subSubKey2] => subSubValue2
)
)
)
AFTER CALL TO nullifyArray():
Array
(
[rootKey1] =>
[rootKey2] =>
[rootArray1] => Array
(
[subKey1] =>
[subArray1] => Array
(
[subSubKey1] =>
[subSubKey2] =>
)
)
)
I hope it helps someone/anyone, and Thank You to all who previously answered the question.
And speed test
This test shows speed when clearing a large array
$a1 = array();
for($i=0;$i<=1000;$i++)
{
$a1['a'.$i] = $i;
}
$b = $a1;
$start_time = microtime(TRUE);
foreach ($a1 as $field => $val) {
$a1[$field]=NULL;
}
$end_time = microtime(TRUE);
$duration = $end_time - $start_time;
var_dump( $duration*1000 );
var_dump('all emelent of array is '.reset($a1));
$start_time = microtime(TRUE);
$allkeys = array_keys($b);
$newarray = array_fill_keys($allkeys, null);
$end_time = microtime(TRUE);
$duration = $end_time - $start_time;
var_dump( $duration*1000 );
var_dump('all emelent of array is '.reset($newarray));
Just do this:
$arrayWithKeysOnly = array_keys($array);
http://php.net/manual/en/function.array-keys.php
EDIT: Addressing comment:
Ok, then do this:
$arrayWithKeysProper = array_flip(array_keys($array));
http://www.php.net/manual/en/function.array-flip.php
EDIT: Actually thinking about it, that probably won't work either.
I need to get the keys from values that are duplicates. I tried to use array_search and that worked fine, BUT I only got the first value as a hit.
I need to get both keys from the duplicate values, in this case 0 and 2. The search result output as an array would be good.
Is there a PHP function to do this or do I need to write some multiple loops to do it?
$list[0][0] = "2009-09-09";
$list[0][1] = "2009-05-05";
$list[0][2] = "2009-09-09";
$list[1][0] = "first-paid";
$list[1][1] = "1";
$list[1][2] = "last-unpaid";
echo array_search("2009-09-09",$list[0]);
You want array_keys with the search value
array_keys($list[0], "2009-09-09");
which will return an array of the keys with the specified value, in your case [0, 2]. If you want to find the duplicates as well, you can first make a pass with array_unique, then iterate over that array using array_keys on the original; anything which returns an array of length > 1 is a duplicate, and the result is the keys in which the duplicates are stored. Something like...
$uniqueKeys = array_unique($list[0])
foreach ($uniqueKeys as $uniqueKey)
{
$v = array_keys($list[0], $uniqueKey);
if (count($v) > 1)
{
foreach ($v as $key)
{
// Work with $list[0][$key]
}
}
}
In array_search() we can read:
If needle is found in haystack more
than once, the first matching key is
returned. To return the keys for all
matching values, use array_keys() with
the optional search_value parameter
instead.
The following combination of function calls will give you all duplicate values:
$a = array(1, 1, 2, 3, 4, 5, 99, 2, 5, 2);
$unique = array_unique($a); // preserves keys
$diffkeys = array_diff_key($a, $unique);
$duplicates = array_unique($diffkeys);
echo 'Duplicates: ' . join(' ', $duplicates) . "\n"; // 1 2 5
You can achieve that using array_search() by using while loop and the following workaround:
while (($key = array_search("2009-09-09", $list[0])) !== FALSE) {
print($key);
unset($list[0][$key]);
}
Source: cue at openxbox at php.net
For one-multidimensional array, you may use the following function to achieve that (as alternative to array_keys()):
function array_isearch($str, $array){
$found = array();
foreach ($array as $k => $v) {
if (strtolower($v) == strtolower($str)) {
$found[] = $k;
}
}
return $found;
}
Source: robertark, php.net
The PHP manual states in the Return Value section of the array_search() function documentation that you can use array_keys() to accomplish this. You just need to provide the second parameter:
$keys = array_keys($list[0], "2009-09-09");
$userdb=Array
(
(0) => Array
(
(uid) => '100',
(name) => 'Sandra Shush',
(url) => 'urlof100'
),
);
$key = array_search(100, array_column($userdb, 'uid'));