Get path from adjacency list data - php

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

Related

Concat values of array with same key

I want to concat values of array with same key
Example:
[0] => Array
(
[0] => A
[1] => XYZ
)
[1] => Array
(
[0] => B
[1] => ABC
)
[2] => Array
(
[0] => A
[1] => LMN
)
[3] => Array
(
[0] => B
[1] => PQR
)
)
Expected output:
[0] => Array
(
[0] => A
[1] => XYZ,LMN
)
[1] => Array
(
[0] => B
[1] => ABC,PQR
)
)
A simple solution uses the PHP function array_reduce():
// The input array you posted in the question
$input = array(
array('A', 'XYZ'),
array('B', 'ABC'),
array('A', 'LMN'),
array('B', 'PQR'),
);
// Reduce the array to a new array that contains the data aggregated as you need
$output = array_reduce(
// Process each $item from $input using a callback function
$input,
// The callback function processes $item; the partial result is $carry
function (array $carry, array $item) {
// Extract the key into a variable
$key = $item[0];
// If the key was encountered before
// then a partial entry already exists in $carry
if (isset($carry[$key])) {
// Append the desired value to the existing entry
$carry[$key][1] .= ','.$item[1];
} else {
// Create a new entry in $carry (copy $item to key $key for quick retrieval)
$carry[$key] = $item;
}
// Return the updated $carry
return $carry;
},
// Start with an empty array (it is known as $carry in the callback function)
array()
);
// $output contains the array you need
Try this:
$final = array();
foreach ($array_items as $item)
{
$key = $item[0];
$found_index = -1;
for ($i=0; $i<count($final); $i++)
{
if ($key == $final[$i][0])
{
$found_index = $i;
break;
}
}
if ($found_index == -1)
{
$final_item = array();
$final_item[0] = $key;
$final_item[1] = $item[1];
$final[] = $final_item;
}
else
{
$final[$found_index][1] .= ",".$item[1];
}
}
We create a new array $final, and loop through your old array $array_items. For each item, we see if there is already an item in $final that has the same [0] index. If it doesn't exist, we create it and add the initial string to the [1] index. If it does exist, we just have to add the string onto the end of the [1] index.
Try it, substituting $array_items for whatever your array is called, let me know if it works.
Check my solution. It should work fine. I hope it will help you much.
$result = $passed_keys = $extended_arr = [];
foreach ($arr as $k => $value) {
for($i = $k + 1; $i < count($arr); $i++){
if ( $value[0] == $arr[$i][0] ){ // compare each array with rest subsequent arrays
$key_name = $value[0];
if (!array_key_exists($key_name, $result)){
$result[$key_name] = $value[1] .",". $arr[$i][1];
} else {
if (!in_array($i, $passed_keys[$key_name])) {
$result[$key_name] .= ",". $arr[$i][1];
}
}
$passed_keys[$key_name][] = $i; // memorizing keys that were passed
}
}
}
array_walk($result, function($v, $k) use(&$extended_arr){
$extended_arr[] = [$k, $v];
});
The result is in $extended_arr
My solution, creates a custom key which makes identifying the letter much easier. This removes the need to continuously iterate through each array, which can become a major resources hog.
<?php
$inital_array = array(
array('A','XYZ'),
array('B','ABC'),
array('A','LMN'),
array('B','PQR')
);
$concat_array = array();
foreach($inital_array as $a){
$key = $a[0];
if( !isset($concat_array[$key]) ){
$concat_array[$key] = array($key,'');
}
$concat_array[$key][1] .= (empty($concat_array[$key][1]) ? '' : ',').$a[1];
}
$concat_array = array_values($concat_array);
echo '<pre>',print_r($concat_array),'</pre>';

php searching in multidimensional array of unknown depth

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
)

How to get the value from serialized array by using preg_match in php

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

count of duplicate elements in an array in php

Hi,
How can we find the count of duplicate elements in a multidimensional array ?
I have an array like this
Array
(
[0] => Array
(
[lid] => 192
[lname] => sdsss
)
[1] => Array
(
[lid] => 202
[lname] => testing
)
[2] => Array
(
[lid] => 192
[lname] => sdsss
)
[3] => Array
(
[lid] => 202
[lname] => testing
)
)
How to find the count of each elements ?
i.e, count of entries with id 192,202 etc
You can adopt this trick; map each item of the array (which is an array itself) to its respective ['lid'] member and then use array_count_value() to do the counting for you.
array_count_values(array_map(function($item) {
return $item['lid'];
}, $arr);
Plus, it's a one-liner, thus adding to elite hacker status.
Update
Since 5.5 you can shorten it to:
array_count_values(array_column($arr, 'lid'));
foreach ($array as $value)
{
$numbers[$value[lid]]++;
}
foreach ($numbers as $key => $value)
{
echo 'numbers of '.$key.' equal '.$value.'<br/>';
}
Following code will count duplicate element of an array.Please review it and try this code
$arrayChars=array("green","red","yellow","green","red","yellow","green");
$arrLength=count($arrayChars);
$elementCount=array();
for($i=0;$i<$arrLength-1;$i++)
{
$key=$arrayChars[$i];
if($elementCount[$key]>=1)
{
$elementCount[$key]++;
} else {
$elementCount[$key]=1;
}
}
echo "<pre>";
print_r($elementCount);
OUTPUT:
Array
(
[green] => 3
[red] => 2
[yellow] => 2
)
You can also view similar questions with array handling on following link
http://solvemyquest.com/count-duplicant-element-array-php-without-using-built-function/
The following code will get the counts for all of them - anything > 1 at the end will be repeated.
<?php
$lidCount = array();
$lnameCount = array();
foreach ($yourArray as $arr) {
if (isset($lidCount[$arr['lid']])) {
$lidCount[$arr['lid']]++;
} else {
$lidCount[$arr['lid']] = 1;
}
if (isset($lnameCount [$arr['lname']])) {
$lnameCount [$arr['lname']]++;
} else {
$lnameCount [$arr['lname']] = 1;
}
}
$array = array('192', '202', '192', '202');
print_r(array_count_values($array));
$orders = array(
array(
'lid' => '',
'lname' => '',
))....
$foundIds = array();
foreach ( $orders as $index => $order )
{
if ( isset( $foundIds[$order['lid']] ) )
{
$orders[$index]['is_dupe'] = true;
$orders[$foundIds[$order['lid']]]['is_dupe'] = true;
} else {
$orders[$index]['is_dupe'] = false;
}
$foundIds[$order['lid']] = $index;
}
Try this code :
$array_count = array();
foreach ($array as $arr) :
if (in_array($arr, $array_count)) {
foreach ($array_count as $key => $count) :
if ($key == $arr) {
$array_count[$key]++;
break;
}
endforeach;
} else {
$array_count[$arr] = 1;
}
endforeach;
Check with in_array() function.

PHP search in Arrays

I have an array named results_array:
var_dump($results_array):
0 => php,mysql,jquery,ruby,html,css,lamp
1 => mouse,keyboard,laptop,pad
2 => table,sofa,caption
3 => control,television,control television,television control
and I have a $q which stands for query, I want to search in the $results_array and remove the items which has nothing to do with the query, so if I set $q=a then results array should be this:
0 => lamp
1 => keyboard,laptop,pad
3 => table,sofa,caption
4 => empty
now, I want to put the above results in each index of the results_array, at the end results_array should be:
0 => lamp
1 => keyboard
2 => laptop
3 => pad
4 => table
5 => sofa
6 => caption
my code is:
foreach($results_array as &$row) {
$row = explode(',', $row);
}
unset($row);
$results_array = call_user_func_array('array_merge_recursive', $results_array);
foreach ($array as $k => $v) {
if(strpos($v, 'a') === false) unset($array[$k]);
}
$results_array = array_values($results_array);
this exactly does what I need, now I set my $q = 'tele co', now after applying the above code set $ = 'tele co', it returns emtpy, but it should not because in:
3 => control,television,control television,television control
'control television,television control' should returned, but it's not, so I change my code to:
foreach($results_array as &$row) {
$row = explode(',', $row);
}
unset($row);
$results_array = call_user_func_array('array_merge_recursive', $results_array);
// HERE IS CHANGED ****
$q = preg_split('/\s+/', trim($q));
foreach ($results_array as $key => $value) {
foreach ($q as $query) {
if (stripos($value, $query) === false) {
unset($results_array[$key]);
break;
}
}
}
// ****
$results_array = array_values($results_array);
it's still not working, by passing $q = 'tele co' I need that 'television control' and 'control television' return, because they both got 'tele' AND 'co' which is in $q
I appreciate any kind of help
Assuming:
$q = 'a c';
$results_array = array(
'php,mysql,jquery,ruby,html,css,lamp',
'mouse,keyboard,laptop,pad',
'table,sofa,caption',
'control,television,control television,television control'
);
Solution:
$result = array_map(function ($element) use ($q) {
$words = explode(',', $element);
return array_filter($words, function ($word) use ($q) {
$qwords = explode(' ', $q);
return count(array_filter($qwords, function ($qword) use ($word) {
return strpos($word, $qword) !== false;
})) > 0;
});
}, $results_array);
Output print_r($result);:
Array
(
[0] => Array
(
[5] => css
[6] => lamp
)
[1] => Array
(
[1] => keyboard
[2] => laptop
[3] => pad
)
[2] => Array
(
[0] => table
[1] => sofa
[2] => caption
)
[3] => Array
(
[0] => control
[2] => control television
[3] => television control
)
)
If I understand your question correctly you're looking for this:
$result = array();
$parts = explode( ' ', $q);
foreach($results_array as $words){
foreach( explode(',', $words) as $word){
$good = true;
foreach( $parts as $p){
if( strpos( $word, $p) === false){
$good = false;
break;
}
}
if( $good){
$result[] = $word;
}
}
}

Categories