Function in_array() - Look for values in multidimensional object array - php

I'm facing a bit of a problem I can't fix myself.
What I'm trying to achieve is sort of a search filter. I have an array which can variate between 1 row to +100 rows.
The array is built like this:
Array
(
[0] => Array
(
[0] => PK customer
[1] => Call number
[2] => Subject of the call
[3] => Date created
[4] => Date changed
)
)
Here is a real version of one of my array's:
stdClass Object ( [ReadOpenCallsResult] => stdClass Object (
[ArrayOfstring] => Array
(
[0] => stdClass Object (
[string] => Array
(
[0] => 180355
[1] => C0000448207
[2] => TESTDOC
[3] => 3-7-2013 14:20:14
[4] => 3-7-2013 14:20:14
)
[1] => stdClass Object (
[string] => Array
(
[0] => 180355
[1] => C0000448209
[2] => TESTDOC
[3] => 2-7-2013 14:20:14
[4] => 2-7-2013 14:20:14
)
)
I have a WCF webservice which generates an array of the result of a function in C# and then sends it to my PHP page.
Now I was testing the in_array function, it works perfectly with an easy array but I can't seem to make it work with a multidimensional array.
I store my array into $_SESSION['searchCalls']
I tested with all kinds of array's but I can't get the 'real' array to work.
I tried it this way:
$key = array_search('180335',$_SESSION['searchCalls']);
And this way
if (in_array('180335',$_SESSION['searchCalls']))
EDIT: I saw some really good examples, but.. is it possible to get all the values in the sub array when someone looks for 'C0000448207' and then get the subject of the call and the datecreated with it?
This is the function which generates the object arrays.
public List<List<string>> ReadOpenCalls(int relation)
{
RidderIQSDK IQSDK = new RidderIQSDK();
SDKRecordset inboundSet = IQSDK.CreateRecordset("R_ACTIONSCOPE", "PK_R_ACTIONSCOPE, DESCRIPTION, DATECREATED, DATECHANGED, CODE", "FK_RELATION = " + relation, "DATECREATED DESC ");
var messages = new List<List<string>>();
List<string> mess = new List<string>();
if (inboundSet != null && inboundSet.RecordCount > 0)
{
inboundSet.MoveFirst();
do
{
List<string> list = new List<string>();
string pkas = inboundSet.Fields["PK_R_ACTIONSCOPE"].Value.ToString();
string code = inboundSet.Fields["CODE"].Value.ToString();
string descr = inboundSet.Fields["DESCRIPTION"].Value.ToString();
string datecreated = inboundSet.Fields["DATECREATED"].Value.ToString();
string datechanged = inboundSet.Fields["DATECREATED"].Value.ToString();
list.Add(pkas);
list.Add(code);
list.Add(descr);
list.Add(datecreated);
list.Add(datechanged);
messages.Add(list);
inboundSet.MoveNext();
}
while (!inboundSet.EOF);
return messages;
}
mess.Add(null);
messages.Add(mess);
IQSDK.Logout();
return messages;
}
I solved it myself already, this is my solution which is kinda nasty but it works.
$roc = array('relation' => $_SESSION['username']);
$rocresponse = $wcfclient->ReadOpenCalls($roc);
$_SESSION['searchCalls'] = $rocresponse;
foreach ($rocresponse->ReadOpenCallsResult as $key => $value){
if (count($value) === 0) {
}
if (count($value) === 1) {
foreach ($value as $key1 => $value1){
if (in_array($searchWord,$value1)){
echo "Value is in it";
}
}
}
else{
foreach($value as $key1 => $value1){
foreach($value1 as $key2 => $value2){
if (array_search($searchWord,$value2)){
print_r($value2);
}
}
}
}
}
I'm always interested in better solutions, and maybe this solution can help someone else out too.

As pointed out by Nisarg this isn't an Array its an Object. Or you need to update your question to show you are accessinng the object.
What if you try something like this
$SearchCalls = $_SESSION['searchCalls'];
if (in_array('180335',$SearchCalls->ReadOpenCallsResult)){
//do some work.
}

Related

Problems changing values in an array/object nested combination array

I don't know what to do to get this done what would like to do. I tried multiple approaches, e.g. I used array_map, array_walk, nested foreach loops with get_object_vars and I worked with json_decode/encode and so on. I always come a little bit further but never reach my goal and I would like to get some guidance from you
Basically when you see the array below, how would you proceed when you want to change some value in the path array for multiple values in the array itself?
My questions:
1) Is it right that I must convert both nested objects to an array first or is this not nesessary to do this? I mean I always get some type conversion error which tells me that I either have everything as an object or array. Is this right?
2) If this mistery is solved, which php array function is the appropriate one to change values in an array(/object)? As I have written above, I tried so many and I don't see the trees in the woods anymore. Which one do you suggest to me to use in a foreach loop?
Array
(
[0] => stdClass Object
(
[doc] => stdClass Object
(
[path] => Array
(
[0] => Bob
[1] => pictures
[2] => food
)
)
)
[1] => stdClass Object
(
[doc] => stdClass Object
(
[path] => Array
(
[0] => Alice
[1] => pictures
[2] => vacations
[3] => rome
)
)
)
)
I would suggest that,
you create an array with keys as new path and value as old path (
path to be replaced).
Loop you path array and check if it is available in above defined array.
If available replace it with key of above defined array.
For example
// array defined as point 1
$change_path_array= array('pics'=>'pictures','meal'=>'food');
// $array is your array.
foreach ($array as $value) {
// loop you path array
for($i=0;$i<count($value->doc->path);$i++){
// check if the value is in defined array
if(in_array($value->doc->path[$i],$change_path_array)){
// get the key and replace it.
$value->doc->path[$i] = array_search($value->doc->path[$i], $change_path_array);
}
}
}
Out Put: picture is replaced with pics and food with meal
Array
(
[0] => stdClass Object
(
[doc] => stdClass Object
(
[path] => Array
(
[0] => Bob
[1] => pics
[2] => meal
)
)
)
[1] => stdClass Object
(
[doc] => stdClass Object
(
[path] => Array
(
[0] => Alice
[1] => pics
[2] => vacations
[3] => rome
)
)
)
)
You can modify the code to check casesensitive.
Example of changing all pictures to photos:
$doc1 = new \stdClass;
$doc1->doc = new \stdClass;
$doc1->doc->path = array('Bob', 'pictures', 'food');
$doc2 = new \stdClass;
$doc2->doc = new \stdClass;
$doc2->doc->path = array('Alice', 'pictures', 'vacations', 'rome');
$documents = array($doc1, $doc2);
/* change all 'pictures' to 'photos' */
foreach ($documents as &$doc) {
foreach ($doc->doc->path as &$element) {
if ($element == 'pictures') {
$element = 'photos';
}
unset($element);
}
unset($doc);
}
print_r($documents);
You can do it like this:
for($i = 0; $i < count($arr); $i++){
$path_array = $arr[$i]->doc->path;
// do your modifications for [i]th path element
// in your case replace all 'Bob's with 'Joe's
$path_array = array_map(function($paths){
if($paths == 'Bob') return 'Joe';
return $paths;
}, $paths_array);
$arr[$i]->doc->path = $path_array;
}

PHP - How can I append/merge onto an array with depth

I have a database query which returns several records, however I would like to append more data to this object by typing the array as an object so that I can for example add more data to the output than the database contains.
I have done some research on this and found some functions such as array_merge but whenever I attempt to use this it gave me issues related to the array's depth and sometimes even created an entirely new array key instead of adding onto the currently existing ones.
This is the data from my database:
Array
(
[Cat] => Array
(
)
[Dog] => Array
(
)
[Rabbit] => Array
(
[0] => stdClass Object
(
[name] => fluffy
[owner] => foobar
)
[1] => stdClass Object
(
[name] => toby
[owner] => foobar
)
[2] => stdClass Object
(
[name] => josie
[owner] => Joseph
)
)
)
I'd like to make it so that every array key which exist have an extra field but other animals remain empty if they do not have any records.
Example:
Array
(
[Cat] => Array
(
[0] => stdClass Object
(
[name] => ralph
[owner] => Joseph
[extra] => some extra data
)
)
[Dog] => Array
(
)
[Rabbit] => Array
(
[0] => stdClass Object
(
[name] => fluffy
[owner] => foobar
[extra] => some extra data
)
[1] => stdClass Object
(
[name] => toby
[owner] => foobar
[extra] => some extra data
)
[2] => stdClass Object
(
[name] => josie
[owner] => Joseph
[extra] => some extra data
)
)
)
The reason I am attempting to merge the two is because I have several helper functions which generate pretty results and I'd like to utilize them rather than output the raw data from the database, the extra data is demonstration of how i'd like to merge onto the current array.
Thanks!
EDIT - Updated code:
function listPets(){
$foo = [];
foreach($pets as $p){
$getPets = $database->Findall("SELECT name, owner, info FROM pets...");
$foo[$p->name] = $getPets;
foreach($foo as $arr){
if(count($arr)){
foreach($arr as $v){
$v->extra = $this->message($getPets->info);
}
}
}
}
return $foo;
}
The solution is:
Loop through the array using foreach loop.
Check if the inner array is empty or not.
If the inner array is not empty then loop through it and append extra property to each of the objects.
So your code should be like this:
// Suppose $array is your original array
foreach($array as $arr){
if(count($arr)){ // check if the array is empty or not
foreach($arr as $v){
$v->extra = 'some extra value'; // append extra property to the object
}
}
}
// display $array
echo '<pre>';
print_r($array);
echo '</pre>';
Here's the demo:
Live Demo
Are you actually trying to merge two arrays or just append some extra information to the non-empty keys in the array of animals?
In the second case, depending on the information you want to add, there's two ways you could go:
Add it to the SELECT statement:
SELECT name, owner, 'extra stuff' as extra FROM ...
Do it like #rajdeep-paul said. Only you can skip the empty array check, if it's empty, foreach will not iterate through it anyway:
foreach ($dbData as $animals) {
foreach ($animals as $animal) {
$animal->extra = 'extra stuff';
}
}
The function below merges arrays & objects:
UPDATE
<?
function fuse_data()
{
$list = func_get_args();
$data = array_shift($list);
$type = gettype($data);
$data = ((array)$data);
foreach ($list as $indx => $item)
{
foreach ($item as $name => $valu)
{
if (!isset($data[$name]) || empty($data[$name]))
{
$data[$name] = $valu;
}
}
}
return (($type == 'object') ? ((object)$data) : $data);
}
?>
Use it like this:
$data = fuse_data($result, $node2, $list3, $foo, $bar);
Edit as you like, it's just a proof of concept.
You can do something like ...
foreach($pets as &$pet) { // passing by reference to manipulate the original array.
if(!empty($pet) && is_array($pet)){ // Checking if the element is an array and not empty
foreach($pet as &$feature){ // Again passing by reference the 2nd dimension
if(is_object($feature)){ // Checking if the element is object to prevent the "Property of non-object" error.
$feature->extra = 'Some value'; // If all is well, we asign the new property to the object.
}
}
}
}
Now even though I think there are better ways to write(optimize) a query than firing it inside a loop!!! but just for the sake of your question, your code should be like..
function listPets(){
$foo = [];
foreach($pets as $p){
$getPets = $database->Findall("SELECT name, owner, info FROM pets...");
$foo[$p->name] = $getPets;
foreach($foo as $arr){
if(is_array($arr) && count($arr)){
foreach($arr as $v){
if(!empty($v) && is_object($v)){
$v->extra = $this->message($getPets->info);
}
}
}
}
}
return $foo;
}

Anonymous PHP function with in_array not working

I have this simple array $tree in PHP that I need to filter based on an array of tags matching those in the array.
Array
(
[0] => stdClass Object
(
[name] => Introduction
[id] => 798162f0-d779-46b6-96cb-ede246bf4f3f
[tags] => Array
(
[0] => client corp
[1] => version 2
)
)
[1] => stdClass Object
(
[name] => Chapter one
[id] => 761e1909-34b3-4733-aab6-ebef26d3fcb9
[tags] => Array
(
[0] => pro feature
)
)
)
I tried using an anonymous function like so:
$selectedTree = array_filter($tree, function($array) use ($selectedTags){
return in_array($array->tags, $selectedTags, true);
});
$selectedTags:
Array
(
[0] => client corp
)
The above is returning empty when I'd expect item 1 to be returned. No error thrown. What am I missing?
In case of in_array($neddle, $haystack). the $neddle must need to be a String, but you're giving an array that is why its not behaving properly.
But if you like to pass array as value of $selectedTags then you might try something like below:
$selectedTree = array_filter($tree, function($array) use ($selectedTags){
return count(array_intersect($array->tags, $selectedTags)) > 0;
});
Ref: array_intersect
If I am reading the question correctly, you need to look at each object in $tree array and see if the tags property contains any of the the elements in $selectedTags
Here is a procedural way to do it.
$filtered = array();
foreach ($tree as $key => $obj) {
$commonElements = array_intersect($selectedTags, $obj->tags);
if (count($commonElements) > 0) {
$filtered[$key] = $obj;
}
}
I was going to also post the functional way of doing this but, see thecodeparadox's answer for that implementation.

Syntax for reading an array in php

I have an array, stored in $array, that with
print "<pre>";
print_r($array);
print "</pre>";
gives an output like this:
Array
(
[device] => Array
(
[0] => Array
(
[#attributes] => Array
(
[name] => Low volt light
[id] => 10
[type] => Z-Wave Switch Multilevel
[value] => 0
[address] => 00016922-018
[code] =>
[canDim] => True
[lastChange] => 26-07-2014 17:31:33
[firstLocation] => Kitchen
[secondLocation] => Main
)
)
[1] => Array
(
[#attributes] => Array
(
[name] => Light
[id] => 11
[type] => Z-Wave Switch Multilevel
[value] => 99
[address] => 00016922-019
[code] =>
[canDim] => True
[lastChange] => 31-07-2014 20:01:05
[firstLocation] => Bedroom
[secondLocation] => Main
)
)
I cannot find my way to access/display for example the value (in this case 0) of device with [id]=>10. What syntax would be the right one in php?
There's not an easy way to do this, without looping through the array.
e.g.
foreach ($array['devices'] as $device) {
if ($device['#attributes']['id'] === $idBeingSearchedFor) {
// Do something with $device.
}
}
Due to the #attributes array key, I'm guessing that this came from XML at some point: You might consider using Simple XML to parse it instead, as you could potentially use XPath then, which does support this type of access.
Alternatively again, you could reformat the array so it could be easily accessed by ID.
For example:
$formattedArray = array();
foreach ($array['devices'] as $device) {
$id = $device['#attributes']['id'];
$formattedArray[$id] = $device;
}
You could then access the device by its ID as follows:
$device = $formattedArray[$idBeingSearchedFor];
You could do it like that:
$id = 10;
$device = array();
foreach($array['device'] as $devices) {
if($devices['#attributes']['id'] == $id) {
$device = $devices['#attributes'];
break;
}
}
echo $device['value'];
Looks like SimpleXML, and if that is the case then those arrays are actually objects that, when put through print_r, look just like arrays. To access them, do the following:
Get straight to the data:
$name = $array->device[0]->attributes()->name;
Or loop through each of the attributes in the first device:
foreach ($array->device[0]->attributes() as $key => $value) {
// Do something with the data. $key is the name of the
// attribute, and then you have the $value.
}
Or you could loop through all the devices:
foreach ($array->device as $device) {
foreach ($device->attributes() as $key => $value) {
// Do something
}
}
It's simple ... try below...
print $array['device'][0]['#attributes']['id'];
or
print $array['device']['0']['#attributes']['id'];

Optimum algorithm to generate keys based on permutations

In my application , I have few parameters (zone_id, startdate, enddate, brand, model) which I get from my UI form . Each of these parameters is an array containing 1 or more parameters .
My form parameters looks something like this :
Array
(
[sel_date_option] => today
[startdate] => 2011-09-19
[enddate] => 2011-09-19
[zone_id] => 1576,1562,1561
[model] => Array
(
[0] => A300
)
[brand] => Array
(
[0] => ACTS
)
)
Now , I want to generate keys which are combinations of these parameters . They would be something like :
[zone_id]_[model]_[brand]_[model]_[startdate]_[enddate]
This reflect all the possible arrangements of the above values .
For the above inputs, I should get the following keys :
1576_ACTS_A300_2011-09-19
1562_ACTS_A300_2011-09-19
1561_ACTS_A300_2011-09-19
Inside of giving the same startdate and enddate once can also enter a period like from 2011-09-19 to 2011-09-21.
What I am doing is I am using nested looping through all the parameter array and then creating a complex array of arrays something like the following :
Array
(
[0] => Array
(
[0] => 1576_DZ_A300
)
[1] => Array
(
[0] => 1576_DZ_A300
[1] => 1562_DZ_A300
)
[2] => Array
(
[0] => 1576_DZ_A300
[1] => 1562_DZ_A300
[2] => 1561_DZ_A300
)
[3] => Array
(
[0] => 1576_DZ_A300
[1] => 1562_DZ_A300
[2] => 1561_DZ_A300
[3] => 1563_DZ_A300
)
)
What I am doing is first I creating an array of all zones as :
Array
(
[0] => 1576
[1] => 1562
[2] => 1561
[3] => 1563
)
Then I am looping it using a nested loop for all the possible models and brands array like this :
function getInventoryData($criteria)
{
$index = "";
if($criteria['zone_id']!='')
{
$zone = explode(',', $criteria['zone_id']);
for($i=0;$i<count($zone);$i++)
{
$index[] .= $zone[$i];
}
echo '<pre>';print_r($index);exit;
}
if(!empty($criteria['model']))
{
foreach($index as $key=>$value)
{
foreach($criteria['model'] as $model)
{
$temparr[] = $index[$key].'_'.$model;
}
$index[$key] = $temparr;
}
}
Now , is there any other efficient method to achieve this ?
Moreover , there is another overhead associated with the above method :
While reading the generated keys , I have to loop through all the levels and in case of large sequence of data , the complexity can be really a matter of concern.
If I understand what you are trying to do correctly, this the most efficient method I can come up with for doing the above:
function getInventoryData ($arr) {
// Make sure all required keys are set
if (!isset($arr['zone_id'],$arr['model'],$arr['brand'],$arr['startdate'],$arr['enddate'])) return FALSE;
// Make a date string for the end of the keys
$dateStr = $arr['startdate'].(($arr['startdate'] == $arr['enddate']) ? '' : '_'.$arr['enddate']);
// Normalise the data
if (!count($arr['zone_id'] = array_unique(explode(',',$arr['zone_id']))) || !count($arr['brand'] = array_unique($arr['brand'])) || !count($arr['model'] = array_unique($arr['model']))) return FALSE;
// Get all possible permutations
$result = array();
foreach ($arr['zone_id'] as $zone) foreach ($arr['brand'] as $brand) foreach ($arr['model'] as $model) $result[] = "{$zone}_{$brand}_{$model}_{$dateStr}";
// Return the result
return $result;
}

Categories