check if value exist in each array multidimensional array - php

i hava multidimensional array
<?php
$data = array(
array(
'name'=>'ahmed',
'job'=>'engineer',
'age'=>25,
'hobbies' => array('drawing','swimming','reading'),
'skills' => array('coding','fasting learning','teaching')
),
array(
'name'=>'Sara',
'job'=>'designer',
'age'=>19,
'skills'=>array('fast learning')
) ,
array(
'name'=>'Ali',
'age'=>25,
'city'=>'cairo'
),
array(
'name'=>'Hossam',
'job'=>'accountant',
'age'=>25,
'city'=>'zagazig'
),
array(
'name'=>'Esraa',
'job'=>'Designer',
'age'=>23,
'city'=>'zagazig',
'hobbies' => array('writing','reading'),
'skills' => array('coding','teaching')
),
);
i want count Arrays where city = "zagazig" or "cairo"
and echo Array Values
Example :
There is [ 1 ] people of City => [ cairo ] :
---------------- Result -----------------------
Name => Ali
Age => 25
City => cairo
if City !exist echo Values
Example :
*---------------- Invaild Data -------------
----------------------- First ---------------
Name => Sara
Job => designer
Age => 19
Skill => fast learning
----------------- Second ----------------
Name => ahmed
Job => engineer
Age => 25
-------------------- Hobbies ----------------
drawing
swimming
reading
-------------------- Skills ----------------
coding
fasting learning
teaching
but i don't know how to loop Multidimensional Array

Given that this is just a raw array, a simple if with foreach should suffice.
First, if the criteria is to get certain entries using city, just use a stripos to search;
$search_string = 'zagazig';
$results = array();
foreach($data as $value) {
if(
!empty($value['city']) &&
(stripos($value['city'], $search_string) !== false)
) {
$results[] = $value;
}
}
This checks if the entry has a city index, then just pushes that array inside a container $result. After gathering the results, just loop it like any normal array:
if(!empty($results)) {
echo 'Number of results: ' , count($results), '<br/> Result <hr/>';
foreach($results as $r) {
echo "
Name: {$r['name']}
Job: {$r['job']}
Age: {$r['age']} <br/>
";
echo !empty($r['hobbies']) ? '<br/>Hobbies: <br/>' . implode('<br/>', $r['hobbies']) : '';
}
}
Output
Of course you can use a <table> tag if you want, this is just an ugly example.
If you like something a little bit different, you can also use array_filter:
Here's an example of it (this also includes some searching inside hobbies and skills):
$search_string = 'coding';
$criteria = 'skills';
$results = array_filter($data, function($e) use ($search_string, $criteria) {
return (
!empty($e[$criteria]) &&
(!is_array($e[$criteria])
? (strpos($e[$criteria], $search_string) !== false)
: (in_array($search_string, $e[$criteria]))
)
);
});
Output

Use php foreach() like:
foreach (array_expression as $value)
{
statement
}
Foreach Documentation

Related

How can I build an multi-dimentional array from a wpdb query return?

I am trying to build a multi-dimensional array from a query return and ran into a problem. Here is a sanitized snippet similar to what I am trying to do. My problem is building the sub array. Any suggestions to get my desired output? I used JSON so it would be more obvious. I can parse an array or JSON.
<?php
// this is my query
global $wpdb;
$locationData = $wpdb->get_results("SELECT
locations.locationID,
locations.location_name,
locations.city,
locations.state,
locations.products,
locations.type,
locations.sku
");
// which returns something like
// [locationID] [location_name] [city] [state] [products] [type] [sku]
// 001 Tulsa Outlet Tulsa OK cakes chocolate 3763
// 001 Tulsa Outlet Tulsa OK cakes lemon 3765
// 001 Tulsa Outlet Tulsa OK sodas coke 4983
// 001 Tulsa Outlet Tulsa OK sodas sprite 4950
// and so on..
// I build an array to be consumed by another function that I created in my plugin:
foreach( $locationData as $key => $location ) {
$output[$row['locationID']] = array(
'locationID' => $row['locationID'],
'location_name' => $row['location_name'],
'products' => array(
// this is where my previous attempts broke down
)
);
$output[$key]['city'] = $location->city;
$output[$key]['state'] = $location->state;
}
// and the $output I need would look like this:
{
"locations" : [
{
"locationID" : "001",
"location_name" : "Tulsa Outlet",
"products" : {
"cakes" : {
"chocolate" : "3763",
"lemon" : "3765"
},
"sodas" : {
"coke" : "4983",
"sprite" : "4950"
}
},
"city" : "Tulsa",
"state" : "ok"
}
]
}
?>
These should help:
$output = [];
foreach ($locationData as $location) {
$locId = $location->locationID;
if (empty($output[$locId])) {
$output[$locId] = [
'locationID' => $location->locationID,
'location_name' => $location->location_name,
'city' => $location->city,
'state' => $location->state,
'products' => [],
];
}
$productType = $location->products;
if (empty($output[$locId]['products'][$productType])) {
$output[$locId]['products'][$productType] = [];
}
$output[$locId]['products'][$productType][$location->type] = $location->sku;
}
Not really sure what you use - $row or $location, so changed everything to $location.
To reindex $output to 0-index array, use array_values.

array, getting title and data of top levels

I currently have an issue with a block of code where a simple change gives me one or the other attribute I'm looking for but not both. I can get the title or the value of the first three levels in this array but not both.
This:
array_walk($promo, function ($e) use (&$results) {
$results['ID']['name']['type'][] = [
'ATT' => $e['ATT'],
'ATT2' => $e['ATT2'],
'ATV' => $e['ATV']
];
});
This gives structure with titles like:
ID
name
type: array(
123,
abc,
blue
)
array_walk($promo, function ($e) use (&$results) {
$ID = &$e['ID'];
$name = &$e['name'];
$type = &$e['type'];
$results[$ID][$name][$type][] = [
'ATT' => $e['ATT'],
'ATT2' => $e['ATT2'],
'ATV' => $e['ATV']
];
});
This gives structure with data but no titles
ID:26
NewList
Task_list: array(
123,
abc,
blue
)
How can I refactor this to give me a list with the first three levels having title and data like so:
ID:26
name:NewList
type:Task_list: array(
123,
abc,
blue
)
Try to modify the array_walk like this :
array_walk($promo, function ($e) use (&$results) {
$ID = &$e['ID'];
$name = &$e['name'];
$type = &$e['type'];
$results['ID'][$ID]['name'][$name]['type'][$type][] = [
'ATT' => $e['ATT'],
'ATT2' => $e['ATT2'],
'ATV' => $e['ATV']
];
});

php recursive function to built menu

i m trying to build recursive menu using PHP but not succeeding
mysql table
menuid name parentid
and my php code
function generateMenubar()
{
$data = Yii::app()->db->createCommand("select * from menu");
$result = $data->queryAll();
$html = '<ul class = "navigation">';
foreach($result as $row)
{
if($row['parentid'] == "0")
{
$html .= '<li><span>'.$row["menuname"].'</span>';
$menu_id = $row['menuid'];
$html .= $this->generateHTML($result,$menu_id,$html);
}
}
return $html;
}
function generateHTML($result,$menu_id,$html)
{
foreach($result as $row_sub)
{
if($menu_id == $row_sub['parentid'])
{
$html .= '<ul><li><span>'.$row_sub['menuname'].'</span>';
$menu_id = $row_sub['menuid'];
$html .= $this->generateHTML($result,$menu_id,$html);
$html .= '</li>';
}
}
return $html.'</ui>';
}
but this loop is not stopping and generating wrong output. it can have sub levels upto n level. i want to make it dynamic cuz levels may change in future any suggestion ?
Your problem is that you do not have a structured result to iterate over. You might have SubElement 2 > 3 > 4 as your first result but 2 > 3 > 1 as your 5th Result. So you can't just iterate over the result once and build your html.
What you want to do (appart from, switching to nested sets, which is what you REALLY want to do wink) is structure your result first.
Iterate over your result and build a nested array to iterate over recusively to build your HTML. To find "where to put your element" in your recursive array you need to recursively check back with your existing array always as well. IF all you store is id and parent id, how to find out what the root element is before you checked ALL elements right?
So i could write the code to do so, but i rather do not because it would be a horrible solution anyway.
To do so more efficiently it would really help if you do not only store your parentid but a level as well.
Then you could store your elements in a two dimensional array storing all elements for each level and then recursively use that array. i.e.
$navigationTempArray = array();
foreach($fakeMySQLResult as $row)
{
if(!array_key_exists($row['level'], $navigationTempArray )) {
$navigationTempArray[$row['level']] = array();
}
if(!array_key_exists($row['parentid'], $navigationTempArray[$row['level']] )) {
$navigationTempArray[$row['level']][$row['parentid']] = array();
}
$navigationTempArray[$row['level']][$row['parentid']][] = $row;
}
now you have an array like this:
array (
0 => array(
'root' => array(
1 => array('title' => 'Start' ...)
2 => array('title' => 'Team' ...)
3 => array('title' => 'Projects' ...)
)
),
1 => array(
2 => array(
4 => array('title' => 'Development' ...)
5 => array('title' => 'Design' ...)
6 => array('title' => 'Sales' ...)
),
3 => array(
7 => array('title' => 'Mayhem' ...)
8 => array('title' => 'X' ...)
)
),
2 => array(
4 => array(
9 => array('title' => 'PHP' ...)
10 => array('title' => 'MySQL' ...)
)
)
)
Now you can iterate over this array recursively, solving every level for every item to infinity ;-)
function returnSubNavigation($id,$level,$fullNavigationArray) {
$html = '';
if(array_key_exists($level, $fullNavigationArray) && array_key_exists($id, $fullNavigationArray[$level])) {
$html .= '<ul>';
foreach($fullNavigationArray[$level][$id] as $subElement) {
$html .= '<li><span>'.$subElement["menuname"].'</span>';
$html .= returnSubNavigation($subElement['id'], $level+1, $fullNavigationArray);
$html .= '</li>';
}
$html .= '</ul>';
}
return $html;
}
echo returnSubNavigation('root', 0, $navigationTempArray);
Here is an online fiddle kind of thing that proves it works
Some people who do not want to use nested sets often store pathes rather than parent id's.
i.e.:
| id | path |
| 1 | 1 |
| 2 | 2 |
| 3 | 1.1 |
| 4 | 1.2 |
| 5 | 2.1 |
| 6 | 3 |
This is a lot easier (cheaper in terms of performance) to iterate over. You can sort it a lot easier. Still, it brings a lot of problems and restrictions.

Give back JSON Array with Sub-Arrays

My table looks like:
id | title | link | kind
------------------------
1 link1 http one
4 link2 http two
2 link9 http one
I want to give back a JSON Array (JSON parsing is not the problem!) which looks like:
one
- link1, http
- link9, http
two
- link2, http
The kind-colum is dynamic so I do not know the actual string. (But it is never (null)!)
What I have:
$links = array();
while($row = mysql_fetch_object($result)) {
$link = array(
'title' => $row->title,
'link' => $row->link,
'kind' => $row->kind
);
$links[] = $link;
}
echo json_encode($links);
That's one array with all columns for each element.
Use $row->kind as an index into the top level array.
$kinds = array('one' => 1, 'two' => 2, ...etc...);
$links = array();
while($row = mysql_fetch_object($result)) {
$link = array(
'title' => $row->title,
'link' => $row->link
);
$links[$kinds[$row->kind]][] = $link;
}
echo json_encode($links);
You can do this in MySQL query:
SELECT CONCAT("[",
GROUP_CONCAT(
CONCAT("{".kind.":'",title ,"'"),
CONCAT(",".kind.":'",link),"'}")
)
,"]") AS json
FROM table_name;

Sorting and storing array returned by a method as parent and child data for displaying nested/multi level comments in codeigniter 2.0

Hey guys I'm trying to learn codeigniter, but once again I'm STUCK and I seek help (as usual :P )
What I need to do?
-> I need to get the data related to a article from the database along with other stuff like the tags for the article and all the comments. I'm thinking of keeping single level nested comments for the article.
Well I'm done with the tag part [link to the answer which helped me with the same : Returning and using multidimensional array of records from database in CodeIgniter 2.0 ] but the comment part is driving me nuts.
Well to get started here is my comments table
Comments
+---------------+-------------+
| Field | Type |
+---------------+-------------+
| commentId | int(10) |
| PostId | int(10) |
| author | varchar(30) |
| email | varchar(30) |
| url | varchar(50) |
| date | datetime |
| comment | text |
| parent | int(10) |
+---------------+-------------+
I'm using the parent field to keep a track of the parent for a nested child comment. By default the value is 0 which means it the parent. Child comment will have the commentid of its parent comment
public function getPost($postName = NULL , $year = NULL, $month = NULL ){
if($postName != NULL && $year != NULL && $month != NULL){
//single post
$this->load->model('comment_model');
$this->db->where('postName',$postName);
$this->db->where('year(date)',$year);
$this->db->where('month(date)',$month);
$q = $this->db->get('mstack_Post');
if($q->num_rows()>0){
$post = $q->result();
foreach ($post as &$p) {
$p->tags = $this->getAllTags($p->postId);
/* getting the comments */
$com = $this->comment_model->getComments($p->postId);
/*echo count($com).' is the total count'; output= 4 */
foreach ($com as &$c) {
/* trying to filter the comment. but all I get is 1 comment as the output*/
if($c->parent==0){
$p->comments->parentComment = $c;
}elseif($c->commentId==$c->parent){
$p->comments->childComment = $c;
}
}
}
return $post;
}else{
return array();
}
}
}
Any help will surely be appreciated.
If you have any other technique /idea to display multi level comments then do let me know. :)
Here is the solution that might be helpfull:
First you need 2 helper recursive function:
// Building comments.
function buildComments($list, $parent = 0)
{
// Creating result array.
$result = array();
//looping...
foreach ($list as $item)
{
//iteration starts with 0 as default.
if ($item->parent == $parent)
{
// add to the result
$result[$item->commentId] = array(
'author' => $item->author,
// ... other definitions
'child' => buildComments($list, $item->commentId) //execute this function for child.
);
}
}
return $result;
}
function printComments($arg, $depth = 1)
{
foreach ($arg as $item)
{
// Printing comment...
echo str_repeat(' ', $depth) . $item['author'] . "<br />\r\n";
// extra echoes...
// if it has a child comment...
if (count($item['child'] > 0))
{
printComments($item['child'], $depth + 1);
}
}
}
A little explaining:
The buildComments() function will starts with rows that parents has 0. Then it will execute itself for child. if child as a child, it will add it. In the end, result will be like this:
$result = array(
1 => array(
'author' => 'John',
'child' => array(
8 => array(
'author' => 'Jane',
'child' => array(
3 => array(
'author' => 'Jamie',
'child => array()
)
)
),
6 => array(
'author' => 'Jackie',
'child => array()
),
9 => array(
'author' => 'Harry',
'child => array()
)
)
),
4 => array(
'author' => 'Jack',
'child' => array()
),
10 => array(
'author' => 'Clark',
'child' => array(
11 => array(
'author => 'Lois',
'child' => array()
)
)
),
12 => array(
'author' => 'Luthor',
'child' => array()
)
);
In the printComments() function we are printing results recursive. for each child, function repeats itself. You will get result like this:
John
Jane
Jamie
Jackie
Harry
Jack
Clark
Lois
Luthor
For more information about recursive functions Look this answer
USAGE
$this->db->where('postName',$postName);
$this->db->where('year(date)',$year);
$this->db->where('month(date)',$month);
$this->db->order_by('parent', 'asc');
$query = $this->db->get('comments');
$comments = buildComments($query->result());
printComments($comments);
that'is that simple...

Categories