Restricting foreach with json to only specific field - php

I have this function
$url = file_get_contents('https://graph.facebook.com/search?q='.spaces($query).'&fields='.$fields.'&limit='.$limit.'&until='.$until);
$j = json_decode($url);
foreach($j->data as $v) {
}
I want to restrict th search to only those data that has as type = status.
I tried to do so:
foreach($j->data->type =='status' as $v) {
But it returns an error.
What is the easy - clean way to achieve this?

You need to iterate over all of them an check inside the loop:
foreach ($j->data as $v) {
if ($v->type == "status") {
// Do whatever you were going to do...
}
}
It is possible to use array_filter() to remove the values you aren't interested in before iterating, but probably not worth the extra effort since the performance gain would be minimal to non-existant.

Related

Seeking advice to optimize the following code chunk. (I need to avoid the IF ELSES)

I have a JSON file with around 30 sub sections. Each subsection will be different. I wanted to convert the data inside it into a format i wanted. The code works fine. But i feel its not optimized 100%.
Client1Insurance, Client2Insurance, ClientFInsurance, FamilyInsurance, Client1Pension, Client2Pension, ClientFPension, FamilyPension.
Above is an example of how this JSON would look like. All above are arrays which have sub arrays inside them. There are around 30 arrays like this.
foreach ($json as $item) {
if (strpos($crmMapKey, "Insurance")) {
$returnArray[] = $this->handleInsurance($item);
} elseif (strpos($crmMapKey, "Pension")) {
$returnArray[] = $this->handlePension($item);
} ... continues the comparison till the json ends
}
I need a way to avoid this long if else comparions which I am not proud of. Will someone be able to suggest a better way to do this?
Thanks.
If they are named the same as you show in your code, something containing Insurance will call handleInsurance, etc. then just get the term and use it in the method call:
preg_match('/Insurance|Pension/', $crmMapKey, $match);
$returnArray[] = $this->{'handle'.$match[0]}($item);
If not then you can use a lookup array:
$lookup = ['Insurance' => 'doSomething', 'Pension' => 'doAnotherThing'];
preg_match('/Insurance|Pension/', $crmMapKey, $match);
$returnArray[] = $this->{'handle'.$lookup[$match[0]]}($item);
Or use the keys in the pattern so you only have to modify the array:
preg_match('/'.implode('|', array_keys($lookup)).'/', $crmMapKey, $match);
The switch I mentioned in a comment might not be the best but works:
switch(true) {
case strpos($crmMapKey, "Insurance") !== false;
$returnArray[] = $this->handleInsurance($item);
break;
case strpos($crmMapKey, "Pension") !== false;
$returnArray[] = $this->handlePension($item);
break;
//etc...
}
Another way would be to call variable based functions.
foreach ($json as $item) {
$returnArray[] = $crmMapKey($item);
}
function Client1Insurance($item) {
// Do something in here.
return $array;
}
function Client2Insurance($item) {
// Do something in here.
return $array;
}
Much more elegant way of doing things I feel.

Is it safe to append to an array in a while loop?

There are numerous questions out there about the safety implications of manipulating an array when using foreach on it. I can't find any questions on doing this in a while loop, though.
So I wonder, is it safe to do this? Below is an example script in PHP and I'm not sure if this is alright.
while ($item = array_pop($array)) {
findMoreItems($item, $array);
}
function findMoreItems($item, &$array) {
// Returns null if no more items are found
$newItem = someFuncFromServer($item);
if ($newItem) {
array_push($array, $newItem);
}
}
By safe I mean: can I be sure that no items are skipped in the loop?
Your code is essentially equivalent to :
$item = array_pop($array);
while ($item) {
findMoreItems($item, $array);
$item = array_pop($array)
}
function findMoreItems($item, &$array) {
// Returns null if no more items are found
$newItem = someFuncFromServer($item);
if ($newItem) {
array_push($array, $newItem);
}
}
Now if you rewrite this in the above way it is obvious that the code will not do anything like copy references or array points or anything like that which is what foreach does. foreach does that because it relies on the internal array pointer which array_pop and array_push do not.

AND in a PHP foreach loop?

Is it possible to have an AND in a foreach loop?
For Example,
foreach ($bookmarks_latest as $bookmark AND $tags_latest as $tags)
You can always use a loop counter to access the same index in the second array as you are accessing in the foreach loop (i hope that makes sense).
For example:-
$i = 0;
foreach($bookmarks_latest as $bookmark){
$result['bookmark'] = $bookmark;
$result['tag'] = $tags_latest[$i];
$i++;
}
That should achieve what you are trying to do, otherwise use the approach sugested by dark_charlie.
In PHP 5 >= 5.3 you can use MultipleIterator.
Short answer: no. You can always put the bookmarks and tags into one array and iterate over it.
Or you could also do this:
reset($bookmarks_latest);
reset($tags_latest);
while ((list(, $bookmark) = each($bookmarks_latest)) && (list(,$tag) = each($tags_latest)) {
// Your code here that uses $bookmark and $tag
}
EDIT:
The requested example for the one-array solution:
class BookmarkWithTag {
public var $bookmark;
public var $tag;
}
// Use the class, fill instances to the array $tagsAndBookmarks
foreach ($tagsAndBookmarks as $bookmarkWithTag) {
$tag = $bookmarkWithTag->tag;
$bookmark = $bookmarkWithTag->bookmark;
}
you can't do that.
but you can
<?php
foreach($keyval as $key => $val) {
// something with $key and $val
}
the above example works really well if you have a hash type array but if you have nested values in the array I recommend you:
or option 2
<?php
foreach ($keyval as $kv) {
list($val1, $val2, $valn) = $kv;
}
No, but there are many ways to do this, e.g:
reset($tags_latest);
foreach ($bookmarks_latest as $bookmark){
$tags = current($tags_latest); next($tags_latest);
// here you can use $bookmark and $tags
}
No. No, it is not.
You'll have to manually write out a loop that uses indexes or internal pointers to traverse both arrays at the same time.
Yes, for completeness:
foreach (array_combine($bookmarks_latest, $tags_latest) as $bookm=>$tag)
That would be the native way to get what you want. But it only works if both input arrays have the exact same length, obviously.
(Using a separate iteration key is the more common approach however.)

php facebook people search how to remove repeat value?

https://graph.facebook.com/search?q=tom&type=user&access_token=2227470867|2.AQD2FG3bzBMEiDV3.3600.1307905200.0-100001799728875|LowLfLcqSZ9YKujFEpIrlFNVZPQ
how to avoid repeat name in facebook people search? in the json code, there have 2 Thomas Lee. Thanks.
foreach ($status_list['data'] as $data) {
echo $data['name']; // not print the same name.
}
$names = Array();
foreach ($status_list['data'] as $data) {
$names[] = $data['name'];
}
$names = array_unique($names); // not print the same name.
foreach ($names as $name) {
echo $name;
}
Here's a fast mashup of how you remove duplicates:
<?php
function existsInArray($list, $key, $value){
foreach($list as $lkey => $lvalue){
if($lvalue[$key] == $value){
return true;
}
}
return false;
}
$sortedUsers = array();
foreach($status_list['data'] as $data){
if(!existsInArray($sortedUsers, "id", $data["id"])){
$sortedUsers[] = $data;
}
}
This will go through the array och users, check if each item exist with the same id in the sorted array. If it doesn't exist, it will be added to the sorted array. Then you have $sortedUsers which doesn't contain any duplicates.
Note: However, this is just proof of concept code. So there are probably a lot of performance optimization that could be done. Also, there are probably some built in functionality to which can do this with less user defined code. Why I showed this is to just explain the process.
Edit: Since this answer got accepted I feel obligated to show something which is a little more high quality than proof of concept code. Also because it got mentioned in the comments that it was inefficient.
So here's easy fix to make this much faster:
$sortedUsers = array();
foreach($status_list['data'] as $data){
$sortedUsers[$data["id"]] = $data;
}
This way it will just overwrite the duplicates and will take away the whole process of comparing each item. In worst case this will be O(n) where as the proof of concept code was O(n ^ (n / 2)) in worst case.

How do you remove an array element in a foreach loop?

I want to loop through an array with foreach to check if a value exists. If the value does exist, I want to delete the element which contains it.
I have the following code:
foreach($display_related_tags as $tag_name) {
if($tag_name == $found_tag['name']) {
// Delete element
}
}
I don't know how to delete the element once the value is found. How do I delete it?
I have to use foreach for this problem. There are probably alternatives to foreach, and you are welcome to share them.
If you also get the key, you can delete that item like this:
foreach ($display_related_tags as $key => $tag_name) {
if($tag_name == $found_tag['name']) {
unset($display_related_tags[$key]);
}
}
A better solution is to use the array_filter function:
$display_related_tags =
array_filter($display_related_tags, function($e) use($found_tag){
return $e != $found_tag['name'];
});
As the php documentation reads:
As foreach relies on the internal array pointer in PHP 5, changing it within the loop may lead to unexpected behavior.
In PHP 7, foreach does not use the internal array pointer.
foreach($display_related_tags as $key => $tag_name)
{
if($tag_name == $found_tag['name'])
unset($display_related_tags[$key];
}
Instead of doing foreach() loop on the array, it would be faster to use array_search() to find the proper key. On small arrays, I would go with foreach for better readibility, but for bigger arrays, or often executed code, this should be a bit more optimal:
$result=array_search($unwantedValue,$array,true);
if($result !== false) {
unset($array[$result]);
}
The strict comparsion operator !== is needed, because array_search() can return 0 as the index of the $unwantedValue.
Also, the above example will remove just the first value $unwantedValue, if the $unwantedValue can occur more then once in the $array, You should use array_keys(), to find all of them:
$result=array_keys($array,$unwantedValue,true)
foreach($result as $key) {
unset($array[$key]);
}
Check http://php.net/manual/en/function.array-search.php for more information.
if you have scenario in which you have to remove more then one values from the foreach array in this case you have to pass value by reference in for each:
I try to explain this scenario:
foreach ($manSkuQty as $man_sku => &$man_qty) {
foreach ($manufacturerSkus as $key1 => $val1) {
// some processing here and unset first loops entries
// here dont include again for next iterations
if(some condition)
unset($manSkuQty[$key1]);
}
}
}
in second loop you want to unset first loops entries dont come again in the iteration for performance purpose or else then unset from memory as well because in memory they present and will come in iterations.
There are already answers which are giving light on how to unset. Rather than repeating code in all your classes make function like below and use it in code whenever required. In business logic, sometimes you don't want to expose some properties. Please see below one liner call to remove
public static function removeKeysFromAssociativeArray($associativeArray, $keysToUnset)
{
if (empty($associativeArray) || empty($keysToUnset))
return array();
foreach ($associativeArray as $key => $arr) {
if (!is_array($arr)) {
continue;
}
foreach ($keysToUnset as $keyToUnset) {
if (array_key_exists($keyToUnset, $arr)) {
unset($arr[$keyToUnset]);
}
}
$associativeArray[$key] = $arr;
}
return $associativeArray;
}
Call like:
removeKeysFromAssociativeArray($arrValues, $keysToRemove);

Categories