I have an array like this, that could have any number of "domain" arrays. I've removed unnecessary keys in this example.
Array
(
[result] => success
[clientid] => 7
[numreturned] => 2
[domains] => Array
(
[domain] => Array
(
[0] => Array
(
[domainname] => example.net
)
[1] => Array
(
[domainname] => example.com
)
)
)
)
I need to figure out how to check this array to see if it contains a domain name.
I'm trying to do something like this:
if(arrayContains("example.com")){
$success = true;
}
I have tried a number of solutions I found on SO, but they don't appear to be working. One example I found used array_key_exists, which is kind of the opposite of what I need.
Any suggestions on how to do this?
Use this function to help you out:
<?php
function recursive_array_search($needle,$haystack) {
foreach($haystack as $key=>$value) {
$current_key=$key;
if($needle===$value OR (is_array($value) && recursive_array_search($needle,$value) !== false)) {
return $current_key;
}
}
return false;
}
?>
This was found in one of the comments in the PHP doc about array_search().
$array = array(
"result" => "success",
"clientid" => 7,
"numreturned" => 2,
"domains" => array(
"domain" => array(
0 => array(
"domainname" => "somedomain.com",
3 => array(
"domainname" => "searchdomanin.com",
),
),
1 => array(
"domainname" => "extwam",
),
)
)
);
$succes = FALSE;
$search = 'searchdomanin.com';
array_walk_recursive($array, function($key, $value) use(&$success, &$search){
if($key === $search){
$success = TRUE;
}
},
[&$key ,&$val]);
if($success){
echo 'FOUND';
}
Works with whatever dimension array you have.
Try something like this:
$domains = $arr['domains'];
foreach($domains AS $domain)
{
foreach($domain AS $internal_arr)
{
if($internal_arr['domainname'] == 'example.net')
{
$success = true;
}
}
}
Related
I want to remove all null or blank value but not false and 0 value from recursive array.
function isNotNull($val) {
if(is_array($val)) {
$ret = array_filter($val, 'isNotNull');
return $ret;
} else {
return (!is_null($val) && $val !== '');
}
}
$arr = array_filter($arr, 'isNotNull');
Input:
$arr = array(
"stringKey" => "Abc",
"boolKey" => false,
"zeroKey" => 0,
"blankKey" => '',
"newArr" => array(
"stringKey2"=>"Abc2",
"boolKey2"=>false,
"zeroKey2" => 0,
"blankKey2"=>"",
"blankArr" => array()
)
);
This give output:
Array
(
[stringKey] => Abc
[boolKey] =>
[zeroKey] => 0
[newArr] => Array
(
[stringKey2] => Abc2
[boolKey2] =>
[zeroKey2] => 0
[blankKey2] =>
[blankArr] => Array
(
)
)
)
But i want to bellow output:
Array
(
[stringKey] => Abc
[boolKey] =>
[zeroKey] => 0
[newArr] => Array
(
[stringKey2] => Abc2
[boolKey2] =>
[zeroKey2] => 0
)
)
I used array_filter with callback function but it only filter simple array not multidimensional array. I don't want to use loop.
You could combine array_map and array_filter in an recursive called function. Something like this could work for you.
function filterNotNull($array) {
$array = array_map(function($item) {
return is_array($item) ? filterNotNull($item) : $item;
}, $array);
return array_filter($array, function($item) {
return $item !== "" && $item !== null && (!is_array($item) || count($item) > 0);
});
}
Don't need to reinvent recursion yourself. You can use RecursiveCallbackFilterIterator:
$iterator = new RecursiveIteratorIterator(
new RecursiveCallbackFilterIterator(
new RecursiveArrayIterator($arr),
function ($value) {
return $value !== null && $value !== '';
}
)
);
$result = iterator_to_array($iterator);
Here is working demo.
You should try to use as much stuff from Standard PHP Library (SPL) as you can.
UPDATE:
As it is stated in the comments, the solution with iterator not actually suits for this purpose.
In the comments to the array_walk_recursive function you can find the implementation of walk_recursive_remove function:
function walk_recursive_remove (array $array, callable $callback) {
foreach ($array as $k => $v) {
if (is_array($v)) {
$array[$k] = walk_recursive_remove($v, $callback);
} else {
if ($callback($v, $k)) {
unset($array[$k]);
}
}
}
return $array;
}
This generalized version of recursion function takes criteria in the form of callback. Having this function you can remove empty elements like this:
$result = walk_recursive_remove($arr, function ($value) {
return $value === null || $value === '';
});
Here is working demo.
Here you require filtering of an array for empty string. In this code below you can add no of checks to filter it recursively. Hope it will work fine.
Try this code snippet here
<?php
ini_set('display_errors', 1);
//Using more complexed sample array for filter it.
$arr = array(
"stringKey" => "Abc",
"boolKey" => false,
"zeroKey" => 0,
"blankKey" => '',
"newArr" => array(
"stringKey2" => "Abc2",
"boolKey2" => false,
"zeroKey2" => 0,
"blankKey2" => "",
"blankArr" => array(
"blankString"=>"",
"zeroKey"=>0,
"blankArr3"=>array()
)
)
);
$result=recursiveFilter($arr);
print_r($result);
function recursiveFilter($value)
{
foreach ($value as $key => $value1)
{
if ($value1 === "") unset($value[$key]);//you can add no. of conditions here.
else if (is_array($value1)) $value[$key] = recursiveFilter($value1);
}
return $value;
}
Output:
Array
(
[stringKey] => Abc
[boolKey] =>
[zeroKey] => 0
[newArr] => Array
(
[stringKey2] => Abc2
[boolKey2] =>
[zeroKey2] => 0
[blankArr] => Array
(
[zeroKey] => 0
[blankArr3] => Array
(
)
)
)
)
I want to remove all null or blank value but not false and 0 value from recursive array.
function isNotNull($val) {
if(is_array($val)) {
$ret = array_filter($val, 'isNotNull');
return $ret;
} else {
return (!is_null($val) && $val !== '');
}
}
$arr = array_filter($arr, 'isNotNull');
Input:
$arr = array(
"stringKey" => "Abc",
"boolKey" => false,
"zeroKey" => 0,
"blankKey" => '',
"newArr" => array(
"stringKey2"=>"Abc2",
"boolKey2"=>false,
"zeroKey2" => 0,
"blankKey2"=>"",
"blankArr" => array()
)
);
This give output:
Array
(
[stringKey] => Abc
[boolKey] =>
[zeroKey] => 0
[newArr] => Array
(
[stringKey2] => Abc2
[boolKey2] =>
[zeroKey2] => 0
[blankKey2] =>
[blankArr] => Array
(
)
)
)
But i want to bellow output:
Array
(
[stringKey] => Abc
[boolKey] =>
[zeroKey] => 0
[newArr] => Array
(
[stringKey2] => Abc2
[boolKey2] =>
[zeroKey2] => 0
)
)
I used array_filter with callback function but it only filter simple array not multidimensional array. I don't want to use loop.
You could combine array_map and array_filter in an recursive called function. Something like this could work for you.
function filterNotNull($array) {
$array = array_map(function($item) {
return is_array($item) ? filterNotNull($item) : $item;
}, $array);
return array_filter($array, function($item) {
return $item !== "" && $item !== null && (!is_array($item) || count($item) > 0);
});
}
Don't need to reinvent recursion yourself. You can use RecursiveCallbackFilterIterator:
$iterator = new RecursiveIteratorIterator(
new RecursiveCallbackFilterIterator(
new RecursiveArrayIterator($arr),
function ($value) {
return $value !== null && $value !== '';
}
)
);
$result = iterator_to_array($iterator);
Here is working demo.
You should try to use as much stuff from Standard PHP Library (SPL) as you can.
UPDATE:
As it is stated in the comments, the solution with iterator not actually suits for this purpose.
In the comments to the array_walk_recursive function you can find the implementation of walk_recursive_remove function:
function walk_recursive_remove (array $array, callable $callback) {
foreach ($array as $k => $v) {
if (is_array($v)) {
$array[$k] = walk_recursive_remove($v, $callback);
} else {
if ($callback($v, $k)) {
unset($array[$k]);
}
}
}
return $array;
}
This generalized version of recursion function takes criteria in the form of callback. Having this function you can remove empty elements like this:
$result = walk_recursive_remove($arr, function ($value) {
return $value === null || $value === '';
});
Here is working demo.
Here you require filtering of an array for empty string. In this code below you can add no of checks to filter it recursively. Hope it will work fine.
Try this code snippet here
<?php
ini_set('display_errors', 1);
//Using more complexed sample array for filter it.
$arr = array(
"stringKey" => "Abc",
"boolKey" => false,
"zeroKey" => 0,
"blankKey" => '',
"newArr" => array(
"stringKey2" => "Abc2",
"boolKey2" => false,
"zeroKey2" => 0,
"blankKey2" => "",
"blankArr" => array(
"blankString"=>"",
"zeroKey"=>0,
"blankArr3"=>array()
)
)
);
$result=recursiveFilter($arr);
print_r($result);
function recursiveFilter($value)
{
foreach ($value as $key => $value1)
{
if ($value1 === "") unset($value[$key]);//you can add no. of conditions here.
else if (is_array($value1)) $value[$key] = recursiveFilter($value1);
}
return $value;
}
Output:
Array
(
[stringKey] => Abc
[boolKey] =>
[zeroKey] => 0
[newArr] => Array
(
[stringKey2] => Abc2
[boolKey2] =>
[zeroKey2] => 0
[blankArr] => Array
(
[zeroKey] => 0
[blankArr3] => Array
(
)
)
)
)
I'm not even sure how to begin wording this question, but basically, I have an array, that looks like this:
Array
(
[0] => /
[1] => /404/
[2] => /abstracts/
[3] => /abstracts/edit/
[4] => /abstracts/review/
[5] => /abstracts/view/
[6] => /admin/
[7] => /admin/ads/
[8] => /admin/ads/clickcounter/
[9] => /admin/ads/delete/
[10] => /admin/ads/edit/
[11] => /admin/ads/list/
[12] => /admin/ads/new/
[13] => /admin/ads/sponsordelete/
[14] => /admin/ads/sponsoredit/
[15] => /admin/ads/sponsornew/
[16] => /admin/ads/stats/
[17] => /admin/boilerplates/
[18] => /admin/boilerplates/deleteboiler/
[19] => /admin/boilerplates/editboiler/
[20] => /admin/boilerplates/newboilerplate/
[21] => /admin/calendar/event/add/
[22] => /admin/calendar/event/copy/
)
And I need to 'reduce' / 'process' it into an array that looks like this:
Array
(
[''] => Array()
['404'] => Array()
['abstracts'] => Array
(
[''] => Array()
['edit'] => Array()
['review'] => Array()
['view'] => Array()
)
['admin'] => Array
(
['ads'] => Array
(
[''] => Array()
['clickcounter'] => Array()
['delete'] =>Array()
['edit'] => Array()
)
)
.....
.....
)
That, if manually initialized would look something like this:
$urlTree = array( '' => array(),
'404' => array(),
'abstracts'=> array( '' => array(),
'edit' => array(),
'review'=> array(),
'view' => array() ),
'admin' => array( 'ads'=> array( '' => array(),
'clickcounter'=> array(),
'delete' => array(),
'edit' => array() ) )
);
I usually stray away from asking straight up for a chunk of code on SO, but does anyone perhaps have any advice / code that can traverse my array and convert it to a hierarchy?
EDIT: Here is the bit I have right now, which, I know is pitifully small, I'm just blanking out today it seems.
function loadUrlData()
{
// hold the raw data, /blah/blah/
$urlData = array();
$res = sql::query( "SELECT DISTINCT(`url`) FROM `pages` ORDER BY `url` ASC" );
while( $row = sql::getarray( $res ) )
{
$urlData[] = explode( '/', substr( $row['url'], 1, -1 ) );
}
// populated, eventually, with the parent > child data
$treeData = array();
// a url
foreach( $urlData as $k=> $v )
{
// the url pieces
foreach( $v as $k2=> $v2 )
{
}
}
// $treeData eventually
return $urlData;
}
Looks rather easy. You want to loop through all lines (foreach), split them into parts (explode), loop through them (foreach) and categorize them.
Since you don't like asking for a chunk of code, I won't provide any.
Update
A very nice way to solve this is to reference the $urlTree (use &), loop through every part of the URL and keep updating a variable like $currentPosition to the current part in the URL tree. Because you use &, you can simply edit the array directly while still using a simple variable.
Update 2
This might work:
// a url
foreach( $urlData as $k=> $v )
{
$currentSection = &$treeData;
// the url pieces
foreach( $v as $k2=> $v2 )
{
if (!isset($currentSection[$v2])) {
$currentSection[$v2] = array();
}
$currentSection = &$currentSection[$v2];
}
}
I know you didn't ask for a chunk of code, but I'd just call this a petit serving:
$map = array();
foreach($urls as $url) {
$folders = explode('/', trim($url, '/'));
applyChain($map, $folders, array());
}
function applyChain(&$arr, $indexes, $value) { //Here's your recursion
if(!is_array($indexes)) {
return;
}
if(count($indexes) == 0) {
$arr = $value;
} else {
applyChain($arr[array_shift($indexes)], $indexes, $value);
}
}
It's fairly simple. We separate each url into its folders (removing trailing and leading slashes) and then work our way down the array chain until we reach the folder mentioned in the URL. Then we place a new empty array there and continue to the next URL.
My version:
$paths = array(
0 => '/',
1 => '/404/',
2 => '/abstracts/',
3 => '/abstracts/edit/',
4 => '/abstracts/review/',
5 => '/abstracts/view/',
6 => '/admin/',
7 => '/admin/ads/',
// ....
);
$tree = array();
foreach($paths as $path){
$tmp = &$tree;
$pathParts = explode('/', rtrim($path, '/'));
foreach($pathParts as $pathPart){
if(!array_key_exists($pathPart, $tmp)){
$tmp[$pathPart] = array();
}
$tmp = &$tmp[$pathPart];
}
}
echo json_encode($tree, JSON_PRETTY_PRINT);
https://ideone.com/So1HLm
http://ideone.com/S9pWw
$arr = array(
'/',
'/404/',
'/abstracts/',
'/abstracts/edit/',
'/abstracts/review/',
'/abstracts/view/',
'/admin/',
'/admin/ads/',
'/admin/ads/clickcounter/',
'/admin/ads/delete/',
'/admin/ads/edit/',
'/admin/ads/list/',
'/admin/ads/new/',
'/admin/ads/sponsordelete/',
'/admin/ads/sponsoredit/',
'/admin/ads/sponsornew/',
'/admin/ads/stats/',
'/admin/boilerplates/',
'/admin/boilerplates/deleteboiler/',
'/admin/boilerplates/editboiler/',
'/admin/boilerplates/newboilerplate/',
'/admin/calendar/event/add/',
'/admin/calendar/event/copy/');
$result = array();
foreach ($arr as $node) {
$result = magic($node, $result);
}
var_dump($result);
function magic($node, $tree)
{
$path = explode('/', rtrim($node, '/'));
$original =& $tree;
foreach ($path as $node) {
if (!array_key_exists($node, $tree)) {
$tree[$node] = array();
}
if ($node) {
$tree =& $tree[$node];
}
}
return $original;
}
<?php
$old_array = array("/", "/404/", "/abstracts/", "/abstracts/edit/", "/abstracts/review/", "/rrl/");
$new_array = array();
foreach($old_array as $woot) {
$segments = explode('/', $woot);
$current = &$new_array;
for($i=1; $i<sizeof($segments); $i++) {
if(!isset($current[$segments[$i]])){
$current[$segments[$i]] = array();
}
$current = &$current[$segments[$i]];
}
}
print_r($new_array);
?>
You might consider converting your text to a JSON string, then using json_decode() to generate the structure.
Is there a better way of doing this PHP code? What I'm doing is looping through the array and replacing the "title" field if it's blank.
if($result)
{
$count = 0;
foreach($result as $result_row)
{
if( !$result_row["title"] )
{
$result[$count]["title"] = "untitled";
}
$count++;
}
}
Where $result is an array with data like this:
Array
(
[0] => Array
(
[title] => sdsdsdsd
[body] => ssdsd
)
[1] => Array
(
[title] => sdssdsfds
[body] => sdsdsd
)
)
I'm not an experienced PHP developer, but I guess that the way I've proposed above isn't the most efficient?
Thanks
if($result) {
foreach($result as $index=>$result_row) {
if( !$result_row["title"] ) {
$result[$index]["title"] = "untitled";
}
}
}
You don't need to count it. It's efficient.
if ($result)
{
foreach($result as &$result_row)
{
if(!$result_row['title'])
{
$result_row['title'] = 'untitled';
}
}
}
Also, you may want to use something other than a boolean cast to check the existence of a title in case some young punk director releases a movie called 0.
You could do something like if (trim($result_row['title']) == '')
Mixing in a little more to #Luke's answer...
if($result) {
foreach($result as &$result_row) { // <--- Add & here
if($result_row['title'] == '') {
$result_row['title'] = 'untitled';
}
}
}
The key is the & before $result_row in the foreach statement. This make it a foreach by reference. Without that, the value of $result_row is a copy, not the original. Your loop will finish and do all the processing but it won't be kept.
The only way to get more efficient is to look at where the data comes from. If you're retrieving it from a database, could you potentially save each record with an "untitled" value as the default so you don't need to go back and put in the value later?
Another alternative could be json_encode + str_replace() and then json_decode():
$data = array
(
0 => array
(
'title' => '',
'body' => 'empty',
),
1 => array
(
'title' => 'set',
'body' => 'not-empty',
),
);
$data = json_encode($data); // [{"title":"","body":"empty"},{"title":"set","body":"not-empty"}]
$data = json_decode(str_replace('"title":""', '"title":"untitled"', $data), true);
As a one-liner:
$data = json_decode(str_replace('"title":""', '"title":"untitled"', json_encode($data)), true);
Output:
Array
(
[0] => Array
(
[title] => untitled
[body] => empty
)
[1] => Array
(
[title] => set
[body] => not-empty
)
)
I'm not sure if this is more efficient (I doubt it, but you can benchmark it), but at least it's a different way of doing the same and should work fine - you have to care about multi-dimensional arrays if you use the title index elsewhere thought.
Perhaps array_walk_recursive:
<?php
$myArr = array (array("title" => "sdsdsdsd", "body" => "ssdsd"),
array("title" => "", "body" => "sdsdsd") );
array_walk_recursive($myArr, "convertTitle");
var_dump($myArr);
function convertTitle(&$item, $key) {
if ($key=='title' && empty($item)) {$item = "untitled";}
}
?>
If you want sweet and short, try this one
$result = array(
array(
'title' => 'foo',
'body' => 'bar'
),
array(
'body' => 'baz'
),
array(
'body' => 'qux'
),
);
foreach($result as &$entry) if (empty($entry['title'])) {
$entry['title'] = 'no val';
}
var_dump($records);
the empty() will do the job, see the doc http://www.php.net/manual/en/function.empty.php
I have the following multidimensional $array:
Array
(
[0] => Array
(
[domain] => example.tld
[type] => 2
)
[1] => Array
(
[domain] => other.tld
[type] => 2
)
[2] => Array
(
[domain] => blaah.tld
[type] => 2
)
)
I simply want to recursively search all the arrays on both key and value, and return true if the key/value was found or false if nothing was found.
Expected output:
search_multi_array($array, 'domain', 'other.tld'); // Will return true
search_multi_array($array, 'type', 'other.tld'); // Will return false
search_multi_array($array, 'domain', 'google.com'); // Will return false
I've figured out a ugly-ugly method to search against the domain against all keys with this function:
function search_multi_array($search_value, $the_array) {
if (is_array($the_array)) {
foreach ($the_array as $key => $value) {
$result = search_multi_array($search_value, $value);
if (is_array($result)) {
return true;
} elseif ($result == true) {
$return[] = $key;
return $return;
}
}
return false;
} else {
if ($search_value == $the_array) {
return true;
}
else
return false;
}
}
Can anyone do better and match both against the key and value in a more elegant way?
If it doesn't go beyond those 2 levels, flipping keys/merging makes life a lot more pleasant:
<?php
$data = array
(
'0' => array
(
'domain' => 'example.tld',
'type' => 2
),
'1' => array
(
'domain' => 'other.tld',
'type' => 2,
),
'2' => array
(
'domain' => 'blaah.tld',
'type' => 2
)
);
$altered = call_user_func_array('array_merge_recursive',$data);
var_dump($altered);
var_dump(in_array('other.tld',$altered['domain']));
var_dump(in_array('other.tld',$altered['type']));
var_dump(in_array('google.com',$altered['domain']));
To go beyond 2nd level, we have to loop once through all the nodes:
$option2 = array();
foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($data)) as $key => $value){
$option2[$key][] = $value;
}
var_dump($option2);
One way is to create a reverse mapping from [domain] => [indices] and from [type] => [indices]. It's probably not going to save you much unless you do lots of searches.
(hint: you probably want to wrap it into a class to prevent inconsistencies in the mappings)
also, anytime you see something like this:
if ($search_value == $the_array) {
return true;
} else {
return false;
}
you can always turn it into:
return $search_value == $the_array;
function search_mutli_array($SearchKey, $SearchValue, $Haystack)
{
$Result = false;
if (is_array($Haystack))
{
foreach ($Haystack as $Key => $Value)
{
if (is_array($Value))
{
if (search_mutli_array($SearchKey, $SearchValue, $Value))
{
$Result = true;
break;
}
}
else if ($SearchKey == $Key && $SearchValue == $Value)
{
$Result = true;
break;
}
}
}
return $Result;
}