I try to select the data of an array that was constructed by json_decode().
In principle it is an multiarray of unknown dimension.
First of all, I want to search recursively for a value in this array. As a next step I want to get some other values of the upper dimension. So here is an example:
I search for: "2345"
....
$json[3][6]['journal']['headline']="news"
$json[3][6]['journal']['article']=2345
....
$json[8]['journal']['headline']="weather"
$json[8]['journal']['article']=2345
....
After that I want to get the value of the element headline (returning "news" and "weather")
It might be that the element 2345 can be found in different dimensions!!!
Someone could probably do this with a RecursiveIteratorIterator object, but I personally have a hard time with iterator objects, so here is a fairly robust system:
<?php
// This will traverse an array and find the
// value while storing the base key
class RecurseLocator
{
public static $saved = array();
public static $find;
public static $trigger;
public static function Initialize($find = false)
{
self::$find = $find;
}
public static function Recursive(array $array)
{
foreach($array as $key => $value) {
if(!isset(self::$trigger) || (isset(self::$trigger) && empty(self::$trigger))) {
if(is_numeric($key))
self::$trigger = $key;
}
if(!is_array($value)) {
if($value == self::$find) {
self::$saved[self::$trigger] = $value;
}
}
if(is_array($value)) {
$value = self::Recursive($value);
if(!is_numeric($key))
self::$trigger = "";
}
$return[$key] = $value;
}
return $return;
}
}
// This class will traverse an array searching
// for a specific key or keys
class RecurseSearch
{
public $data;
public $compare;
public function Find($array = '',$find,$recursive = true)
{
$find = (is_array($find))? implode("|",$find):$find;
if(is_array($array)) {
foreach($array as $key => $value) {
if(preg_match("/$find/",$key))
$this->compare[$key] = $value;
if($recursive == true) {
if(!is_array($value)) {
if(preg_match("/$find/",$key)) {
$this->data[$key][] = $value;
}
$array[$key] = $value;
}
else {
if(preg_match("/$find/",$key))
$this->data[$key][] = $this->Find($value,$find);
$array[$key] = $this->Find($value,$find);
}
}
else {
if(preg_match("/$find/",$key))
$this->data[$key] = $value;
}
}
$this->data = (isset($this->data))? $this->data:false;
return $this;
}
}
}
// This function just wraps the RecurseSearch class
function get_key_value($array = array(), $find = array(),$recursive = true)
{
$finder = new RecurseSearch();
return $finder->Find($array,$find,$recursive);
}
USAGE:
$json[3][6]['journal']['headline'] = "news";
$json[3][6]['journal']['article'] = 2345;
$json[8]['journal']['headline'] = "weather";
$json[8]['journal']['article'] = 2345;
$json[4][1]['journal']['headline'] = "news";
$json[4][1]['journal']['article'] = 22245;
$json[5]['journal']['headline'] = "weather";
$json[5]['journal']['article'] = 233345;
// Set the search criteria
RecurseLocator::Initialize(2345);
// Traverse the array looking for value
$arr = RecurseLocator::Recursive($json);
// If found, will be stored here
$iso = RecurseLocator::$saved;
/* $iso looks like:
Array
(
[3] => 2345
[8] => 2345
)
*/
// Loop through the $iso array
foreach($iso as $key => $value) {
// Save to new array your search results
$new[] = get_key_value($json[$key],array("headline","article"),true);
}
/* $new looks like:
Array
(
[0] => RecurseSearch Object
(
[data] => Array
(
[headline] => Array
(
[0] => news
)
[article] => Array
(
[0] => 2345
)
)
[compare] => Array
(
[headline] => news
[article] => 2345
)
)
[1] => RecurseSearch Object
(
[data] => Array
(
[headline] => Array
(
[0] => weather
)
[article] => Array
(
[0] => 2345
)
)
[compare] => Array
(
[headline] => weather
[article] => 2345
)
)
)
*/
?>
Just as a side note, the above class stores multiple found in the [data], and then stores them also in the [compare], however the [compare] will overwrite itself if multiple same-keys are found in one array where as [data] will just keep adding values.
just create a function for compile unknown array. try this
$json[1][6]['journal']['headline']="news";
$json[1][6]['journal']['article']=2345;
$json[3][6]['journal']['headline']="HOT";
$json[3][6]['journal']['article']=2345;
$json[8]['journal']['headline']="weather";
$json[8]['journal']['article']=2345;
$json[10]['journal']['headline']="weather";
$json[10]['journal']['article']=2345;
$GLOBALS['list_scan'] = array();
$result = array();
foreach ($json as $key => $value)
{
if (is_array($value)) {
_compile_scan($key, $value);
}
}
echo "<pre>";
print_r($GLOBALS['list_scan']);
echo "</pre>";
$search = "2345";
$keyword = "article";
$keyFinder = "headline";
foreach ($GLOBALS['list_scan'] as $key => $value)
{
if ($value == $search)
{
$addr = substr($key, 0, -(strlen($keyword))).$keyFinder;
if (!empty($GLOBALS['list_scan'][$addr]))
{
$result[] = $GLOBALS['list_scan'][$addr];
}
}
}
echo "<pre>";
print_r($result);
echo "</pre>";
function _compile_scan($index, $value)
{
$pointer =& $GLOBALS['list_scan'];
foreach ($value as $key => $val)
{
$temp = '';
$temp = $index.'|'.$key;
if (is_array($val))
{
// $pointer[$temp] = $val;
_compile_scan($temp, $val);
}
else $pointer[$temp] = $val;
}
}
output:
Array
(
[1|6|journal|headline] => news
[1|6|journal|article] => 2345
[3|6|journal|headline] => HOT
[3|6|journal|article] => 2345
[8|journal|headline] => weather
[8|journal|article] => 2345
[9|journal|headline] => Others
[9|journal|article] => 234521
)
Array
(
[0] => news
[1] => HOT
[2] => weather
)
Related
I will use this function in this loop :
while ($nbrDocument < 12 && $nbrTags > 0)
{
$tmpDocuments = $this
->get('fos_elastica.manager')
->getRepository('AppBundle:Document')
->findFromTag();
$tagPossibilities = $this->generateTagPossibilities($userTags, $nbrTags);
foreach ($tmpDocuments as $document)
{
$present = true;
foreach ($tagPossibilities as $tags)
{
foreach ($tags as $tag)
{
if (!in_array($tag, $document->getTag()))
{
$present = false;
break;
}
}
if ($present) {
break;
}
}
$nbrDocument ++;
array_push($documents, $$document);
}
$nbrTags--;
}
And I need to create the method generateTagPossibilities.
The first parameter contains an array of string data, and the second is the size
of the possibilities I need to have.
For exemple, if I have [1][2][3][4] in my array and $nbrTag = 4, this function should return [1][2][3][4], if $nbrTag = 3, it should return [[1][2][3]] [[1][3][4]] [[2][3][4]] ...
Got any idea of how I can do that ?
You can use the following functions :
function array_hash($a)
{
$s = '';
foreach($a as $v)
{
$s.=$v.'-';
}
return hash('sha256',$s);
}
function removeOne($setList)
{
$returnSetList = array();
$hashList = array();
foreach($setList as $set)
{
foreach($set as $k=>$v)
{
$tmpSet = $set;
unset($tmpSet[$k]);
$hash = array_hash($tmpSet);
if(!in_array($hash, $hashList))
{
$returnSetList[] = $tmpSet;
$hashList[] = $hash;
}
}
}
return $returnSetList;
}
function generateTagPossibilities($userTags, $nbrTags)
{
$aUserTags = array($userTags);
$cUserTags = count($userTags);
if($nbrTags==$cUserTags)
return $aUserTags;
for($i=0; $i<($cUserTags-$nbrTags); $i++)
$aUserTags = removeOne($aUserTags);
return $aUserTags;
}
// Example !
$a = array(1,2,3,4);
print_r(generateTagPossibilities($a,2));
/*
Array
(
[0] => Array
(
[2] => 3
[3] => 4
)
[1] => Array
(
[1] => 2
[3] => 4
)
[2] => Array
(
[1] => 2
[2] => 3
)
[3] => Array
(
[0] => 1
[3] => 4
)
[4] => Array
(
[0] => 1
[2] => 3
)
[5] => Array
(
[0] => 1
[1] => 2
)
)
*/
I have an array (data from adjacency table) and it looks like:
Array
(
[0] => Array
(
[id] => 1
[name] => Anniversary
[parent] => 0
)
[1] => Array
(
[id] => 12
[name] => New arrives
[parent] => 1
)
[2] => Array
(
[id] => 13
[name] => Discount
[parent] => 12
)
[3] => Array
(
[id] => 6
[name] => Birthday
[parent] => 0
)
)
And I'm looking for the way to retrieve my path by ID;
For example: getPath(13): Anniversary->New arrives->Discount;
For example: getPath(12): Anniversary->New arrives;
For example: getPath(1): Anniversary;
For example: getPath(6): Birthday;
How can I do this?
Thanks!
function getpath($id, $arr, $level = 0) {
$result = array();
foreach($arr as $key => $value){
if($id == $value['id']){
$result[] = $value['name'];
$id = $value['parent'];
if($id != 0){
$result = array_merge($result, getpath($id, $arr, $level+1));
}else{
break;
}
}
}
return $level ? $result : implode('->',array_reverse($result));
}
echo getpath(13,$arr);
Consider this array,
$input = [
['id'=>1, 'name'=>'Anniversary', 'parent'=>0],
['id'=>12, 'name'=>'New arrives', 'parent'=>1],
['id'=>13, 'name'=>'Discount', 'parent'=>12],
['id'=>6, 'name'=>'Birthday', 'parent'=>0]
];
and this function,
function path($element_id, $input, $ids = [])
{
if(!$ids) // for performance, make this once and pass it around
{
$ids = array_column($input, 'id'); // array containing only 'id's of $input
}
$current_key = array_search($element_id, $ids); // search for $input variable's current key
unset($ids[$current_key]); // unsetting used keys to make above array search faster next time
$current_element = $input[$current_key]; // get current element as array from $input
$names[] = $current_element['name']; // create an array containing current element
if($current_element['parent'] != 0) // check if current element have parent
{
$names[] = path($current_element['parent'], $input, $ids); // call this function, let it return string, append it to $names
}
return implode(' ⟶ ', array_reverse($names)); // make final return, seprate by ⟶
}
Reading echo path(13, $input); will return
Anniversary ⟶ New arrives ⟶ Discount
Here is minified version of the same function
function path($a,$b,$c=[]){if(!$c){$c=array_column($b,'id');}$d=array_search($a,$c);unset($c[$d]);$e=$b[$d];$f[]=$e['name'];if($e['parent']!=0){$f[]=path($e['parent'],$b,$c);}return implode(' ⟶ ',array_reverse($f));}
Thanks to code reviewers Loufylouf and Quill
$find = 13;
$path = array();
function FindById ($arr, $find) {
$k = null;
foreach($arr as $key => $item)
if ($item['id'] == $find)
{ $k = $key; break; }
return $k;
}
if ( false === ($k = FindById($arr, $find))) die("not found");
while (true) {
array_unshift($path, $arr[$k]['name']);
if( ! $arr[$k]['parent']) break;
if(false === ($k = FindById($arr, $arr[$k]['parent']))) die("illegal structure");
}
echo implode('->', $path);
I have this array:
Array
(
[datas] => Array
(
[General] => Array
(
[0] => Array
(
[id] => logo
[size] => 10
)
)
[Rooms] => Array
(
[0] => Array
(
[id] => room_1
[size] => 8
)
[1] => Array
(
[id] => room_2
[size] => 8
)
[2] => Array
(
[id] => room_3
[size] => 8
)
)
)
)
I need to update it when I receive some info like this:
$key = 'room_3';
$toChange = '9';
So in my array, I want to change the size of room_3.
I will always edit the same element (i.e. size).
What I tried:
// Function to communicate with the array
getDatas($array, 'room_3', '9');
function getDatas($datas, $got, $to_find) {
foreach ($datas as $d) {
if (array_search($got, $d)) {
if (in_array($to_find, array_keys($d))) {
return trim($d[$to_find]);
}
}
}
}
But it does not work...
Could you please help me ?
Thanks.
function getDatas($datas, $got, $to_find) {
foreach($datas['datas'] as $key => $rows) {
foreach($rows as $number => $row) {
if($row['id'] == $got) {
// u can return new value
return $row['size'];
// or you can change it and return update array
$datas['dates'][$key][$number]['size'] = $to_find; // it should be sth like $new value
return $datas;
}
}
}
}
function changeRoomSize (&$datas, $roomID, $newSize ){
//assuming that you have provided valid data in $datas array
foreach($datas['datas']['Rooms'] as &$room){
if($room['id'] == $roomID){
$room['size'] = $newSize;
break;//you can add break to stop looping after the room size is changed
}
}
}
//--- > define here your array with data
//and then call this function
changeRoomSize($data,"room_3",9);
//print the results
var_dump($data);
It's a 3-dimensional array, if you want to change the value, do like this:
$key = 'room_3';
$toChange = '9';
$array['datas'] = getRooms($array['datas'], $key, $toChange);
function getRooms($rooms, $key, $toChange) {
foreach($rooms as $k1=>$v1) foreach ($v1 as $k2=>$v2) {
if ($v2['id'] == $key)) {
$rooms[$k1][$k2]['size'] = $toChange;
}
}
return $rooms;
}
print_r($array);
I need to get the value from the serialized array by matching the index value.My unserialized array value is like
Array ( [info1] => test service [price_total1] => 10
[info2] => test servicing [price_total2] => 5 )
I need to display array like
Array ( [service_1] => Array ([info]=>test service [price_total] => 10 )
[service_2] => Array ([info]=>test servicing [price_total] => 5 ))
buy i get the result like the below one
Array ( [service_1] => Array ( [price_total] => 10 )
[service_2] => Array ( [price_total] => 5 ) )
my coding is
public function getServices($serviceinfo) {
$n = 1;
$m = 1;
$matches = array();
$services = array();
print_r($serviceinfo);
if ($serviceinfo) {
foreach ($serviceinfo as $key => $value) {
if (preg_match('/info(\d+)$/', $key, $matches)) {
print_r($match);
$artkey = 'service_' . $n;
$services[$artkey] = array();
$services[$artkey]['info'] = $serviceinfo['info' . $matches[1]];
$n++;
}
if ($value > 0 && preg_match('/price_total(\d+)$/', $key, $matches)) {
print_r($matches);
$artkey = 'service_' . $m;
$services[$artkey] = array();
$services[$artkey]['price_total'] = $serviceinfo['price_total' . $matches[1]];
$m++;
}
}
}
if (empty($services)) {
$services['service_1'] = array();
$services['service_1']['info'] = '';
$services['service_1']['price_total'] = '';
return $services;
}
return $services;
}
I try to print the matches it will give the result as
Array ( [0] => info1 [1] => 1 ) Array ( [0] => price_total1 [1] => 1 )
Array ( [0] => info2 [1] => 2 ) Array ( [0] => price_total2 [1] => 2 )
Thanks in advance.
try this. shorted version and don't use preg_match
function getServices($serviceinfo) {
$services = array();
if (is_array($serviceinfo) && !empty($serviceinfo)) {
foreach ($serviceinfo as $key => $value) {
if(strpos($key, 'info') === 0){
$services['service_'.substr($key, 4)]['info']=$value;
}elseif (strpos($key, 'price_total') === 0){
$services['service_'.substr($key, 11)]['price_total']=$value;
}
}
}
return $services;
}
$data = array('info1'=>'test service','price_total1'=>10,'info2'=>'test servicing','price_total2'=>5);
$service = getServices($data);
print_r($service);
I'm trying to find a way to return the value of an array's parent key.
For example, from the array below I'd like to find out the parent's key where $array['id'] == "0002".
The parent key is obvious because it's defined here (it would be 'products'), but normally it'd be dynamic, hence the problem. The 'id' and value of 'id' is known though.
[0] => Array
(
[data] =>
[id] => 0000
[name] => Swirl
[categories] => Array
(
[0] => Array
(
[id] => 0001
[name] => Whirl
[products] => Array
(
[0] => Array
(
[id] => 0002
[filename] => 1.jpg
)
[1] => Array
(
[id] => 0003
[filename] => 2.jpg
)
)
)
)
)
A little crude recursion, but it should work:
function find_parent($array, $needle, $parent = null) {
foreach ($array as $key => $value) {
if (is_array($value)) {
$pass = $parent;
if (is_string($key)) {
$pass = $key;
}
$found = find_parent($value, $needle, $pass);
if ($found !== false) {
return $found;
}
} else if ($key === 'id' && $value === $needle) {
return $parent;
}
}
return false;
}
$parentkey = find_parent($array, '0002');
Since you have a tree structure either of a BFS or DFS can do it. Since the structure is variable a recursive solution would work well. Simply return a sentinel when you find the value, then return the key in the caller.
function array_to_xml($array, $rootElement = null, $xml = null) {
$_xml = $xml;
if ($_xml === null) {
$_xml = new SimpleXMLElement($rootElement !== null ? $rootElement : '<root/>');
}
$has_int_key = 0;
foreach ($array as $k => $v) {
if (is_array($v)) {
if(is_int($k)){
$this->array_to_xml($v, $k, $_xml->addChild($rootElement));
}
else {
foreach($v as $key=>$value) {
if(is_int($key)) $has_int_key = 1;
}
if ($has_int_key) {
$this->array_to_xml($v, $k, $_xml);
} else {
$this->array_to_xml($v, $k, $_xml->addChild($k));
}
}
}
else {
$_xml->addChild($k, $v);
}
}
return $_xml->asXML();
}