delete all values from an array while keeping keys intact - php

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.

Related

How can you count the number keys in an array that have a non-empty corresponding value? [duplicate]

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;
}

PHP - Get first and last key and value from array

From a given array (eg: $_SERVER), I need to get the first and last key and value. I was trying use array_shift to get first value and key but what I get is value.
Here is the $_SERVER array:
print_r($_SERVER, true))
And I tried with:
echo array_shift($_SERVER);
With PHP >= 7.3 you can get it fast, without modification of the array and without creating array copies:
$first_key = array_key_first($_SERVER);
$first_value = $_SERVER[$first_key];
$last_key = array_key_last($_SERVER);
$last_value = $_SERVER[$last_key];
See array_key_first and array_key_last.
It's not clear if you want the value, or the key. This is about as efficient as it gets, if memory usage is important.
If you want the key, use array_keys. If you want the value, just refer to it with the key you got from array_keys.
$count = count($_SERVER);
if ($count > 0) {
$keys = array_keys($_SERVER);
$firstKey = $keys[0];
$lastKey = $keys[$count - 1];
$firstValue = $array[$firstKey];
$lastValue = $array[$lastKey];
}
You can't use $count - 1 or 0 to get the first or last value in keyed arrays.
You can do a foreach loop, and break out after the first one:
foreach ( $_SERVER as $key => $value ) {
//Do stuff with $key and $value
break;
}
Plenty of other methods here. You can pick and choose your favorite flavor there.
Separate out keys and values in separate arrays, and extract first and last from them:
// Get all the keys in the array
$all_keys = array_keys($_SERVER);
// Get all the values in the array
$all_values = array_values($_SERVER);
// first key and value
$first_key = array_shift($all_keys);
$first_value = array_shift($all_values);
// last key and value (we dont care about the pointer for the temp created arrays)
$last_key = end($all_keys);
$last_value = end($all_values);
/* you can use reset function after end function call
if you worry about the pointer */
What about this:
$server = $_SERVER;
echo array_shift(array_values($server));
echo array_shift(array_keys($server));
reversed:
$reversed = array_reverse($server);
echo array_shift(array_values($reversed));
echo array_shift(array_keys($reversed));
I think array_slice() will do the trick for you.
<?php
$a = array_slice($_SERVER, 0, 1);
$b = array_slice($_SERVER, -1, 1, true);
//print_r($_SERVER);
print_r($a);
print_r($b);
?>
OUTPUT
Array ( [TERM] => xterm )
Array ( [argc] => 1 )
DEMO: https://3v4l.org/GhoFm

Push something into a specified position in an array in php

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');

How to remove all instances of duplicated values from an array

I know there is array_unique function, but I want to remove duplicates. Is there a built-in function or do I have to roll my own.
Example input:
banna, banna, mango, mango, apple
Expected output:
apple
You can use a combination of array_unique, array_diff_assoc and array_diff:
array_diff($arr, array_diff_assoc($arr, array_unique($arr)))
You can use
$singleOccurences = array_keys(
array_filter(
array_count_values(
array('banana', 'mango', 'banana', 'mango', 'apple' )
),
function($val) {
return $val === 1;
}
)
)
See
array_count_values — Counts all the values of an array
array_filter — Filters elements of an array using a callback function
array_keys — Return all the keys or a subset of the keys of an array
callbacks
Just write your own simple foreach loop:
$used = array();
$array = array("banna","banna","mango","mango","apple");
foreach($array as $arrayKey => $arrayValue){
if(isset($used[$arrayValue])){
unset($array[$used[$arrayValue]]);
unset($array[$arrayKey]);
}
$used[$arrayValue] = $arrayKey;
}
var_dump($array); // array(1) { [4]=> string(5) "apple" }
have fun :)
If you want to only leave values in the array that are already unique, rather than select one unique instance of each value, you will indeed have to roll your own. Built in functionality is just there to sanitise value sets, rather than filter.
You want to remove any entries that have duplicates, so that you're left with only the entries that were unique in the list?
Hmm it does sound like something you'll need to roll your own.
There is no existing function; You'll have to do this in two passes, one to count the unique values and one to extract the unique values:
$count = array();
foreach ($values as $value) {
if (array_key_exists($value, $count))
++$count[$value];
else
$count[$value] = 1;
}
$unique = array();
foreach ($count as $value => $count) {
if ($count == 1)
$unique[] = $value;
}
The answer on top looks great, but on a side note: if you ever want to eliminate duplicates but leave the first one, using array_flip twice would be a pretty simple way to do so. array_flip(array_flip(x))
Only partially relevant to this specific question - but I created this function from Gumbo's answer for multi dimensional arrays:
function get_default($array)
{
$default = array_column($array, 'default', 'id');
$array = array_diff($default, array_diff_assoc($default, array_unique($default)));
return key($array);
}
In this example, I had cached statuses and each one other than the default was 0 (the default was 1). I index the default array from the IDs, and then turn it into a string. So to be clear - the returned result of this is the ID of the default status providing it's in the same part of the multi dimensional array and not the key of it
PHP.net http://php.net/manual/en/function.array-unique.php
array array_unique ( array $array [, int $sort_flags = SORT_STRING ] )
Takes an input array and returns a new array without duplicate values.
New solution:
function remove_dupes(array $array){
$ret_array = array();
foreach($array as $key => $val){
if(count(array_keys($val) > 1){
continue;
} else {
$ret_array[$key] = $val;
}
}

Assigning an array element to a variable with the same name?

I'd like to be able to extract some array elements, assign each of them to a variable and then unset these elements in the array.
Let's say I have
$myarray = array ( "one" => "eins", "two" => "zwei" , "three" => "drei") ;
I want a function suck("one",$myarray)as a result the same as if I did manually:
$one = "eins" ;
unset($myarray["one"]) ;
(I want to be able to use this function in a loop over another array that contains the names of the elements to be removed, $removethese = array("one","three") )
function suck($x, $arr) {
$x = $arr[$x] ;
unset($arr[$x]) ;
}
but this doesn't work. I think I have two prolbems -- how to say "$x" as the variable to be assigned to, and of function scope. In any case, if I do
suck("two",$myarray) ;
$two is not created and $myarray is unchanged.
Try this:
$myarray = array("one" => "eins", "two" => "zwei" , "three" => "drei");
suck('two', $myarray);
print_r($myarray);
echo $two;
function suck($x, &$arr) {
global $$x;
$$x = $arr[$x];
unset($arr[$x]);
}
Output:
Array
(
[one] => eins
[three] => drei
)
zwei
I'd build an new array with only the key => value pairs you want, and then toss it at extract().
You can do
function suck($x, $arr) {
$$x = $arr[$x] ;
unset($arr[$x]) ;
}
, using variable variables. This will only set the new variable inside the scope of "suck()".
You can also have a look at extract()
Why not this:
foreach ($myarray as $var => $val) {
$$var = $val;
unset($myarray[$var]);
echo "$var => ".$$var . "\n";
}
Output
one => eins
two => zwei
three => drei
If I've understood the question, you have two problems
The first is that you're setting the value of $x to be the value in the key-value pair. Then you're unsetting a key that doesn't exist. Finally, you're not returning anything. Here's what I mean:
Given the single element array $arr= array("one" => "eins") and your function suck() this is what happens:
First you call suck("one", $arr). The value of $x is then changed to "eins" in the line $x=$arr[$x]. Then you try to unset $x (which is invalid because you don't have an array entry with the key "eins"
You should do this:
function suck($x, $arr)
{
$tmp = $arr[$x];
unset($arr[$x]);
return $tmp
}
Then you can call this function to get the values (and remove the pair from the array) however you want. Example:
<?php
/* gets odd numbers in german from
$translateArray = array("one"=>"eins", "two"=>"zwei", "three"=>"drei");
$oddArray = array();
$oddArray[] = suck($translateArray,"one");
$oddArray[] = suck($translateArray, "three");
?>
The result of this is the array called translate array being an array with elements("eins","drei");
HTH
JB

Categories