I am making a search based on name of the product. It does work actually and it does find the product according search, however the problem is when I have several products with the same name it only shows me the first one. How could it be optimized? I would appreciate your help.
<?php
//DATA coming from the browser
$sSearch = $_GET['search'];
//TURN it into UPPERCASE
strtoupper( $sSearch );
//GETTING FROM FILE:
$sajProducts = file_get_contents( 'products.txt' );
$ajProducts = json_decode( $sajProducts );
$matchfound = false;
//LOOPING THROUGH THE ARRAY OF PRODUCTS
for ( $i=0; $i< count( $ajProducts ); $i++ ) {
if ( $sSearch == $ajProducts[$i]->name ) {
$jSearchResult = $ajProducts[$i];
$matchfound = true;
break;
}
}
//if there is a match display the product
if ( $matchfound ) {
echo json_encode ( $jSearchResult );
exit;
}
//if not display ALL products
else {
echo json_encode( $ajProducts );
exit;
}
?>
And the JSON products.text file:
[
{
"id": "59d278cae7017",
"name": "A",
"price": "1",
"quantity": 3,
"image": "img_webshop\/productimage-59d74304917c2.jpg"
},
{
"id": "59d27e20c8028",
"name": "A",
"price": "2",
"quantity": 3,
"image": "img_webshop\/productimage-59d743233c0cf.jpg"
},
{
"id": "59d6a7ae16d15",
"name": "A",
"price": "3",
"quantity": 2,
"image": "img_webshop\/productimage-59d743392fbb5.jpg"
},
{
"id": "59d6d6ee5f752",
"name": "A",
"price": "4",
"quantity": 4,
"image": "img_webshop\/productimage-59d74352d5b94.jpg"
},
{
"id": "59d743d207bd5",
"name": "B",
"price": "5",
"quantity": 1,
"image": "img_webshop\/productimage-59d743d1e6e64.jpg"
},
{
"id": "59d74451225ac",
"name": "B",
"price": "6",
"quantity": 1,
"image": "img_webshop\/productimage-59d7445120871.jpg"
},
{
"id": "59e0d95cd4111",
"name": "B",
"price": "4",
"quantity": "5",
"image": "img_webshop\/productimage-59e0d95cd2c4b.jpg"
},
{
"id": "59e0d992d1f3b",
"name": "C",
"price": "6",
"quantity": "5",
"image": "img_webshop\/productimage-59e0d992d19be.jpg"
},
{
"id": "59e0d9c59fbf2",
"name": "D",
"price": "4",
"quantity": "5",
"image": "img_webshop\/productimage-59e0d9c59f1a5.jpg"
}
]
Collect all matching result in an array and then return it in JSON.
$jSearchResult = array();
for ( $i=0; $i< count( $ajProducts ); $i++ ) {
if ( $sSearch == $ajProducts[$i]->name ) {
$jSearchResult[] = $ajProducts[$i];
$matchfound = true;
//break;
}
}
So, here after foreach loop completes the iteration for all json values, we will have final array of all the matches in $jSearchResult
then return it:
if ( $matchfound ) {
echo json_encode ( $jSearchResult );
exit;
}
Use this code:
$matchfound = false;
$jSearchResult = array();
//LOOPING THROUGH THE ARRAY OF PRODUCTS
for ( $i=0; $i< count( $ajProducts ); $i++ ) {
if ( $sSearch == $ajProducts[$i]->name ) {
$jSearchResult[] = $ajProducts[$i];
$matchfound = true;
}
}
Instead of this:
$matchfound = false;
//LOOPING THROUGH THE ARRAY OF PRODUCTS
for ( $i=0; $i< count( $ajProducts ); $i++ ) {
if ( $sSearch == $ajProducts[$i]->name ) {
$jSearchResult = $ajProducts[$i];
$matchfound = true;
break;
}
}
Related
I tried to parse a JSON using PHP from url. I need a list of item that have no children - means children field should be empty array and parent_id shouldn't be 0 - means not be parents.
JSON:
{
"body": {
"data": [
{
"id": 1,
"name": "car",
"parent_id": "0",
"children": [
{
"id": 2,
"name": "bmw",
"parent_id": "1",
"children": [
{
"id": 4,
"name": "bmw i8",
"parent_id": "2",
"children": []
}
]
},
{
"id": 3,
"name": "mustang",
"parent_id": "1",
"children": []
}
]
},
{
"id": 5,
"name": "clothes",
"parent_id": "0",
"children": []
},
{
"id": 6,
"name": "mobile",
"parent_id": "0",
"children": [
{
"id": 7,
"name": "apple",
"parent_id": "6",
"children": [
{
"id": 9,
"name": "Iphone 12 pro",
"parent_id": "7",
"children": []
},
{
"id": 10,
"name": "Iphone 11",
"parent_id": "7",
"children": []
}
]
},
{
"id": 8,
"name": "Xiaomi",
"parent_id": "6",
"children": []
}
]
}
]
}
}
Output Expected:
[4,3,9,10,8]
This is my php code that i tried and doesn't work.
$CategoryUrl = file_get_contents(self::CATEGORY_URL,true);
$array = json_decode($CategoryUrl,true);
$list = array();
foreach( $array['body']['data'] as $value ){
if (($value['parent_id'] != 0) && empty($value['children'])) {
foreach( $value['children'] as $val ){
$list[] = $val;
}
}
}
print_r($list);
It is indeed a little tricky to keep track of parent ID values and children call using array_walk_recursive as it jumps directly to its children. However, this can be still accomplished with your own recursive version like below. Keep checking with parent_id and children count. If both constraints satisfy, add them to $result, else keep calling children recursively.
<?php
$str = '{"body":{"data":[{"id":1,"name":"car","parent_id":"0","children":[{"id":2,"name":"bmw","parent_id":"1","children":[{"id":4,"name":"bmw i8","parent_id":"2","children":[]}]},{"id":3,"name":"mustang","parent_id":"1","children":[]}]},{"id":5,"name":"clothes","parent_id":"0","children":[]},{"id":6,"name":"mobile","parent_id":"0","children":[{"id":7,"name":"apple","parent_id":"6","children":[{"id":9,"name":"Iphone 12 pro","parent_id":"7","children":[]},{"id":10,"name":"Iphone 11","parent_id":"7","children":[]}]},{"id":8,"name":"Xiaomi","parent_id":"6","children":[]}]}]}}';
$data = json_decode($str,true);
$result = [];
function walkRecursive($data,&$result){
foreach($data as $entry){
if($entry['parent_id'] != 0 && count($entry['children']) == 0){
$result[] = $entry['id'];
}else{
walkRecursive($entry['children'],$result);
}
}
}
walkRecursive($data['body']['data'],$result);
print_r($result);
We can solve this problem by function call recursive algorithm,
hope it clear for you
$CategoryUrl = file_get_contents(self::CATEGORY_URL,true);
$array = json_decode($CategoryUrl, true);
$items = $array['body']['data'];
$list = [];
findParentIds(items, $list);
// doSomething
print_r($list);
/**
* passe by ref (list)
* #param array $children
* #param $list
*/
function findParentIds(array $children, & $list)
{
foreach ($children as $child) {
// use case 1: has no children and parent_id is 0 , just continue
if (empty($child['children']) && $child['parent_id'] == "0") {
continue;
}
// use case 2: has no children and parent_id is 0 , it's parent item
if (empty($child['children']) && $child['parent_id'] != "0") {
array_push($list, $child['id']);
}
// has children and parent_id is not 0 , recall function to treat use case 1 and 2 ..
findParentIds($child['children'], $list);
}
}
I'm retrieving data from a database and pushing it to arrays then use json_encode() to output in json format. I have ended up having the data in this format.
[
{
"category_id": "1",
"category_name": "Construction Materials"
},
{
"items": [
{
"id": "1",
"item_name": "Wire Mesh",
"price": "459",
"image_url": null
},
{
"id": "2",
"item_name": "Cement",
"price": "700",
"image_url": null
},
{
"id": "3",
"item_name": "Barbed Wire",
"price": "3000",
"image_url": null
},
{
"id": "4",
"item_name": "Iron sheet",
"price": "200",
"image_url": null
}
]
},
{
"category_id": "2",
"category_name": "Plumbing"
},
Here is what I want to achieve:
[
{
"category_id": "1",
"category_name": "Construction Materials"
"items": [
{
"id": "1",
"item_name": "Wire Mesh",
"price": "459",
"image_url": null
},
{
"id": "2",
"item_name": "Cement",
"price": "40",
"image_url": null
},
{
"id": "3",
"item_name": "Barbed Wire",
"price": "3000",
"image_url": null
},
{
"id": "4",
"item_name": "Iron sheet",
"price": "200",
"image_url": null
}
]
},
{
"category_id": "2",
"category_name": "Plumbing"
},
How can I achive this in php. Is it possible to edit the contents of the main array? how can I add "items" after "category_name"
Regards..
$array = json_decode($yourJson);
$arrayLength = count($array);
$finalArray = [];
for ($i=0; $i < $arrayLength; $i+=2) {
$finalArray[] = $array[$i] + $array[$i + 1];
}
$backToJson = json_encode($finalArray);
Alternative to Mattijs's answer.
function get_first_property($object) {
$properties = array_keys(get_object_vars($object));
return reset($properties);
}
function object_merge($object1, $object2) {
return (object) array_merge((array) $object1, (array) $object2);
}
// loop through each of the array objects
$previous_first_property = null;
foreach ($array as $i => $object) {
$first_property = get_first_property($object);
// merge if the 1st property is "items", and the previous 1st was "category_id"
if ($first_property == "items" && $previous_first_property == "category_id") {
$array[$i - 1] = object_merge($array[$i - 1], $array[$i]);
unset($array[$i]);
}
$previous_first_property = $first_property;
}
I have the following PHP code which searches the array by the key name and returns result equals to the search. Just for curiosity how can I do that, that no matter what I search for the result will be elements where the name key value equals "A"? Shortly how can I retrieve elements where name is "A" ?
I tried the following but does´t work:
$jSearchResult[] = $ajProducts[$i]->name = "A";
Please help me cause I just simply can´t figure out how to retrive elements of an array by key value, however I am sure it must be something very simple.
<?php
//DATA coming from the BROWSER
$sSearch = $_GET['search'];
//TURN it into UPPERCASE
strtoupper( $sSearch );
//GETTING from the TEXT FILE:
$sajProducts = file_get_contents( 'products.txt' );
$ajProducts = json_decode( $sajProducts );
$match_found = false;
//Collect all matching result in an array
$jSearchResult = array();
//LOOPING THROUGH THE ARRAY OF PRODUCTS
for ( $i=0; $i< count( $ajProducts ); $i++ ) {
if ( $sSearch == $ajProducts[$i]->name ) {
$jSearchResult[] = $ajProducts[$i]->name;
$match_found = true;
}
}
//if there is a match display the product
if ( $match_found ) {
echo json_encode ( $jSearchResult );
exit;
}
//if not display ALL products
else {
echo json_encode ( $ajProducts );
exit;
}
?>
$ajProducts looks like this:
[
{
"id": "59d278cae7017",
"name": "A",
"price": "1",
"quantity": 2,
"image": "img_webshop\/productimage-59d74304917c2.jpg"
},
{
"id": "59d27e20c8028",
"name": "A",
"price": "2",
"quantity": 1,
"image": "img_webshop\/productimage-59d743233c0cf.jpg"
},
{
"id": "59d6a7ae16d15",
"name": "A",
"price": "3",
"quantity": 2,
"image": "img_webshop\/productimage-59d743392fbb5.jpg"
},
{
"id": "59d6d6ee5f752",
"name": "A",
"price": "4",
"quantity": 1,
"image": "img_webshop\/productimage-59d74352d5b94.jpg"
},
{
"id": "59d743d207bd5",
"name": "B",
"price": "5",
"quantity": 1,
"image": "img_webshop\/productimage-59d743d1e6e64.jpg"
},
{
"id": "59d74451225ac",
"name": "B",
"price": "6",
"quantity": 0,
"image": "img_webshop\/productimage-59d7445120871.jpg"
},
{
"id": "59e0d992d1f3b",
"name": "C",
"price": "6",
"quantity": 2,
"image": "img_webshop\/productimage-59e725ac79583.jpg"
}
]
There is a php function that does just that: http://php.net/array_filter
$searchResult = array_filter($ajProducts, function ($product) {
return $product->name === 'A';
});
This will get you all objects in $ajProducts having name property set to 'A'.
To see if there're any results:
$matchFound = !empty($searchResult);
If you want to match elements where the name key value equals "A", then you can just make a check with value of name key is equal to "A" like -
foreach ($ajProducts as $ajProduct ) {
if ( "A" == $ajProduct->name ) {
$jSearchResult[] = $ajProduct->name;
$match_found = true;
}
}
I have the following performance problem in PHP code. An external API that I cannot edit, returns a JSON array like this one:
[{"name": "Name 1", "code": "Code 1", "attribute1": "Black", "attribute2": "32", "price": "10"},
{"name": "Name 2", "code": "Code 2", "attribute1": "Yellow", "attribute2": "", "price": "15"},
{"name": "Name 1", "code": "Code 3", "attribute1": "Yellow", "attribute2": "32", "price": "20"},....
]
I want to group this by name and reformat it to a JSON array like this:
[{
"name": "Name 1",
"available_attributes": [ "size", "color" ],
"variations": [
{ "attributes": { "size": "32", "color": "Black" }, "price": "10", "code": "Code 1"},
{ "attributes": { "size": "32", "color": "Yellow" }, "price": "20", "code": "Code 3"}
]
}, {
"name": "Name 2",
"available_attributes": [ "color" ],
"variations": [ { "attributes": { "color": "Yellow" }, "price": "15", "code": "Code 2"}]
}]
My solution is ugly and time-consuming since I used a simple brute force to iterate on the response and then again every time on the array to update the one I have already there.
So, I am looking for a solution focused on performance and speed.
Edit. This is my code. The only difference is that in case of both attributes being empty, instead of the variations and available_attributes arrays, it has the price and the sku only.
function cmp( $a, $b ) {
if ( $a['name'] == $b['name'] ) {
return 0;
}
return ( $a['name'] < $b['name'] ) ? - 1 : 1;
}
function format_products_array($products) {
usort( $products, "cmp" );
$formatted_products = array();
$new = true;
$obj = array();
for ( $i = 0; $i < count( $products ); $i++ ) {
if ( $new ) {
$obj = array();
$attr = array();
$obj['available_attributes'] = array();
$obj['variations'] = array();
$obj['name'] = $products[$i]['name'];
if ( $products[$i]['attribute1'] != '' ) {
array_push( $obj['available_attributes'], 'color' );
$attr['color'] = $products[$i]['attribute1'];
}
if ( $products[$i]['attribute2'] != '' ) {
array_push( $obj['available_attributes'], 'size' );
$attr['size'] = $products[$i]['attribute2'];
}
}
if ( $products[ $i ]['name'] == $products[ $i + 1 ]['name']) {
$new = false;
$attr['size'] = $products[$i]['attribute2'];
$attr['color'] = $products[$i]['attribute1'];
if ( empty($obj['available_attributes']) ) {
$obj['price'] = $products[$i]['price'];
} else {
$var = array();
$var['price'] = $products[$i]['price'];
$var['code'] = $products[$i]['code'];
$var['attributes'] = $attr;
array_push($obj['variations'], $var);
}
} else {
$new = true;
if ( empty($obj['available_attributes']) ) {
$obj['price'] = $products[$i]['price'];
}
$attr['size'] = $products[$i]['attribute2'];
$attr['color'] = $products[$i]['attribute1'];
$var['attributes'] = $attr;
array_push($obj['variations'], $var);
array_push($formatted_products, $obj);
}
}
return $formatted_products;
}
A faster solution is when generating the array to store the unique identifies or each object eg to generate:
[
"Name1":{
"name": "Name 1",
"code": "Code 1",
"available_attributes": [ "size", "color" ],
"variations": [
{ "attributes": { "size": "32", "color": "Black" }, "price": "10"},
{ "attributes": { "size": "32", "color": "Yellow" }, "price": "20"}
]
},
"Name2": {
"name": "Name 2",
"code": "Code 2",
"available_attributes": [ "color" ],
"variations": [ { "attributes": { "color": "Yellow" }, "price": "15"}]
}]
OR
[
"Code 1":{
"name": "Name 1",
"code": "Code 1",
"available_attributes": [ "size", "color" ],
"variations": [
{ "attributes": { "size": "32", "color": "Black" }, "price": "10"},
{ "attributes": { "size": "32", "color": "Yellow" }, "price": "20"}
]
},
"Code 2": {
"name": "Name 2",
"code": "Code 2",
"available_attributes": [ "color" ],
"variations": [ { "attributes": { "color": "Yellow" }, "price": "15"}]
}]
Afterwards (optionally)remove any association.
Afterwards you may store them in a memcached/redis then when you need to re-retrieve the same data then just look in redis/memcached first.
So it may be time consuming at first but afterwards it will be ready to do that so they will be only on "unlucky" guy/girl who will do the very same thing.
In case it is extreemely time consuming loops then use a worker to generate theese data ans store them in an document-based storage such as mongodb/couchdb afterwards the site will look on the ready made document.
I have PHP code as shown below which will print:
id:3deep:2path:image31.jpg
id:4deep:2path:image32.jpg
when I input deep = 2. However I would like to get parent array of this deep which is id = 2. Is there any way that I can do this?
Note:
Please see the result when I input deep as below:
> Deep = 1
ID = 0
ID = 1
ID = 2
ID = 7
ID = 8
> Deep = 2
ID = 2
ID = 3
ID = 4
> Deep = 3
ID = 4
ID = 5
ID = 6
Please check my code online.
PHP:
$obj = '{
"images": {
"deep": "1",
"id": "0",
"path": "image1.jpg",
"image": [
{
"deep": "1",
"id": "1",
"coordinate": "(x,y),(x,y)",
"path": "image2.jpg"
},
{
"deep": "1",
"id": "2",
"coordinate": "(x,y),(x,y)",
"path": "image3.jpg",
"image": [
{
"deep": "2",
"id": "3",
"coordinate": "(x,y),(x,y)",
"path": "image31.jpg"
},
{
"deep": "2",
"id": "4",
"coordinate": "(x,y),(x,y)",
"path": "image32.jpg",
"image": [
{
"deep": "3",
"id": "5",
"coordinate": "(x,y),(x,y)",
"path": "image321.jpg"
},
{
"deep": "3",
"id": "6",
"coordinate": "(x,y),(x,y)",
"path": "image322.jpg"
}
]
}
]
},
{
"deep": "1",
"id": "7",
"coordinate": "(x,y),(x,y)",
"path": "image4.jpg"
},
{
"deep": "1",
"id": "8",
"coordinate": "(x,y),(x,y)",
"path": "image5.jpg"
}
]
}
}';
$objArray = json_decode($obj,true);
$deep = 2;
$arr = all($objArray['images'], $deep);
display($arr);
function all($a, $d){
$temp = array();
if(is_array($a)){
foreach($a as $v){
all($v, $d);
}
if(isset($a['deep']) && $d == $a['deep']){
$temp['id'] = $a['id'];
$temp['deep'] = $a['deep'];
$temp['path'] = $a['path'];
$s =
'id:'.$a['id'].
'deep:'.$a['deep'].
'path:'.$a['path'];
display($s);
}
}
return ;
}
function display($a){
echo "<pre>";
print_r($a);
echo "</pre>";
}
Idk exactly what you want, but I changed your code a bit to filter in a nicer way and it adds the parent key to each $image so you can reference that afterwards.
You can set the $deep = null paramater to just add the parent to the image instead of filtering.
I hope you don't mind I changed the code style a bit, easier to read ( I hope :D )
Here's the code within phpfiddle: http://phpfiddle.org/main/code/8q0-c43
<?php
$obj = '{
"images": {
"deep": "1",
"id": "0",
"path": "image1.jpg",
"image": [
{
"deep": "1",
"id": "1",
"coordinate": "(x,y),(x,y)",
"path": "image2.jpg"
},
{
"deep": "1",
"id": "2",
"coordinate": "(x,y),(x,y)",
"path": "image3.jpg",
"image": [
{
"deep": "2",
"id": "3",
"coordinate": "(x,y),(x,y)",
"path": "image31.jpg"
},
{
"deep": "2",
"id": "4",
"coordinate": "(x,y),(x,y)",
"path": "image32.jpg",
"image": [
{
"deep": "3",
"id": "5",
"coordinate": "(x,y),(x,y)",
"path": "image321.jpg"
},
{
"deep": "3",
"id": "6",
"coordinate": "(x,y),(x,y)",
"path": "image322.jpg"
}
]
}
]
},
{
"deep": "1",
"id": "7",
"coordinate": "(x,y),(x,y)",
"path": "image4.jpg"
},
{
"deep": "1",
"id": "8",
"coordinate": "(x,y),(x,y)",
"path": "image5.jpg"
}
]
}
}';
$objArray = json_decode($obj, true);
function filter_deep(array $input, $deep = null, $parent = null) {
// store $results so we can return it
$result = array();
// loop over the $input
foreach ($input as $image) {
// set the parent passed alogn
$image['parent'] = $parent;
// add $image to $result if 'deep' == $deep
if ($deep === null || $image['deep'] == $deep) {
$result[] = $image;
}
// if the $image contains more child images recursively run this function again
// and merge the result with what we already have
if (isset($image['image']) && is_array($image['image'])) {
$result = array_merge($result, filter_deep($image['image'], $deep, $image));
}
}
return $result;
}
function display_image($image) {
return "id:{$image['id']} deep:{$image['deep']} path:{$image['path']} parent_id:{$image['parent']['id']} <br />\n";
}
// loop over the images that have deep == 2 and display them
foreach (filter_deep(array($objArray['images']), 2) as $image) {
echo display_image($image);
}
?>