I have a result set from a query that gives me an object that has dozens of fields, the below example is a subset:
[79] => stdClass Object
(
[name] => John Doe
[email] => john#doe.com
[ext] => 4004
[options] => stdClass Object
(
[type] => friend
[rating] => Excellent
[context] => default
)
[address] => 123 Anywhere St
)
Instead of plowing through each field, because I only want a handful of them, I am trying to use an array to get what i want:
$fields = array('name','email','options->type','options->rating','address');
so then i do:
foreach ($result as $k => $v){
foreach ($fields as $kk => $vv){
echo $kk. " - " . $v->$kk."<br>";
}
}
Which gives me field name and its value.
name - John Doe
email - john#doe.com
address - 123 Anywhere St.
However, anything in that sub object(options) is giving me a blank result.
You can use a recursive function providing that you don't mind changing the format of your $fields var to include arrays. In my opinion this makes it easier to read anyway, and easier to handle in code.
The benefit of using a recursive function is that it will handle any depth.
$o = (object) [
'name' => 'John Doe',
'email' => 'john#doe.com',
'ext' => 4004,
'options' => (object) [
'type' => 'friend',
'rating' => 'Excellent',
'context' => 'default',
'any' => (object) [
'depth' => (object) [
'will' => 'work'
]
]
],
'address' => '123 Anywhere St'
];
$fields = [
'name',
'email',
'options' => [
'type',
'rating',
'any' => [
'depth' => [
'will'
]
]
],
'address'
];
function getObjectProps($o, $fields, $parent = '') {
if (strlen($parent)) {
$parent .= '->';
}
foreach ($fields as $k => $v) {
if (is_array($v)) {
getObjectProps($o->{$k}, $v, $parent . $k);
} else {
echo $parent . $v . ' - ' . $o->{$v} . '<br/>';
}
}
}
getObjectProps($o, $fields);
Output:
name - John Doe
email - john#doe.com
options->type - friend
options->rating - Excellent
options->any->depth->will - work
address - 123 Anywhere St
Use a multidimensionnal array for $fields and change your foreach loop a little bit:
$fields = [
'name',
'email',
'options' => [
'type',
'rating'
],
'address'
];
foreach ($result as $obj) {
foreach ($fields as $k => $v) {
if (is_array($v)) {
foreach ($v as $vv) {
echo $vv . ' - ' . $obj->$k->$vv . '<br>';
}
} else {
echo $v . ' - ' . $obj->$v . '<br>';
}
}
}
Here's what I came up with in the meantime
$someObject = new stdClass();
$someObject->name = 'Dale';
$someObject->options = new stdClass();
$someObject->options->address = 'The Address';
$fields = ['name', 'options' => ['address']];
function toArray($object, $fields) {
$return = [];
foreach($fields as $fieldKey => $fieldValue) {
if(!is_array($fieldValue)) {
$return [] = $object->$fieldValue;
}
else
{
$return = array_merge($return, toArray($object->$fieldKey, $fieldValue));
}
}
return $return;
}
print_r(toArray($someObject, $fields));
Try this code:
$newResult = array_intersect_key((array)$result, array_flip($fields));
There is no easy way to access property like the way you are trying. But there's a symfony's property access component which you can use. But if you are focusing to use your own method then you might love the following code. I ran this code in PHP 7.2
$data = (object) [
'name' => 'John Doe',
'email' => 'john#doe.com',
'ext' => 4004,
'options' => (object) [
'type' => "friend",
'rating' => 'Excellent',
'context' => 'default'
],
'address' => '123 Anywhere St'
];
$fields = array('name','email','options->type','options->rating','address');
/*** way of initializing
$response = []; // get array value here
$response = ""; // get string value here
***/
$response = ""; //string value here... as output
/*** Don't you think that the below code now is clean and reusable? ***/
array_map(function($key) use($data, &$response) {
$value = array_reduce(explode('->', $key), function ($o, $p) {
return $o->$p;
}, $data);
is_array($response) ? ($response[$key] = $value) : ($response .= $key . ' - ' . $value . '<br>');
}, $fields);
echo $response;
In the above code if you initialize $response as an empty array then you'll get array as output. And if you initialize that as an empty string then you'll get string output. And I think instead of using for loop, use array_map and array_reduce, they work like magic and reduce your code too.
String as output:
Array as ouput:
Related
my array image just like this, if subarray "name" is empty or null i want delete array, how to do that ?
here my current script
$data = array();
$fixedData = array();
$countyName = array();
$numrow = 2;
echo "<pre>";
// insert to tb participant => 1
foreach($sheet as $key => $row){
$data[] = array(
'name' => $this->split_name($row['B']),
'phone' => $row['D'],
'mobile' => $row['E'],
'institution' => $row['F'],
'departement' => $row['G'],
'address' => $row['H'],
'country' => $row['I'],
);
$numrow++;
}
unset($data[0]); //delete first row
$data = array_values($data);
//loop search data
var_dump ($data);
die();
Assume that you have the following data set,
$array = [
[
'name' => 'not null', 'phone' => 12546
],[
'name' => '', 'phone' => 852147
],[
'name' => null, 'phone' => 96325874
],[
'name' => 'have value', 'phone' => 12546
],
];
You can filter the nulled or empty values like several ways :
1-
foreach ($array as $key => &$value) {
if (empty($value['name']) || is_null($value['name'])) {
$value = null;
}
}
$array = array_filter($array);
2-
$newData = [];
foreach ($array as $key => $value) {
if (!empty($value['name']) && !is_null($value['name'])) {
$newData[] = $value;
}
}
3- using array_walk
$newData = [];
array_walk($array, function ($value, $key) use (&$newData) {
if (!empty($value['name']) && !is_null($value['name'])) {
$newData[] = $value;
}
});
4- using array_filter
$newData = array_filter($array, function ($value) {
if (!empty($value['name']) && !is_null($value['name'])) {
return $value;
}
});
<?php
$data = array();
$fixedData = array();
$countyName = array();
$numrow = 2;
echo "<pre>";
// insert to tb participant => 1
foreach($sheet as $key => $row){
if($this->split_name($row['B'])!=='' && $this->split_name($row['B'])!==NULL){
$data[] = array(
'name' => $this->split_name($row['B']),
'phone' => $row['D'],
'mobile' => $row['E'],
'institution' => $row['F'],
'departement' => $row['G'],
'address' => $row['H'],
'country' => $row['I'],
);
$numrow++;
}
}
//loop search data
var_dump ($data);
die();
I simple put an if condition inside your loop so you can check if your value is null or empty and if it is then you don't fill your new array. Also moved your counter inside the if so you increment it only in a success array push
A more "elegant" way for your if condition is this as well:
if (!empty($this->split_name($row['B'])) && !is_null($this->split_name($row['B'])))
I'm trying to wrap my head around how to accomplish this…
I have an that's something like:
$contributors = array(
[0] => array(
[name] => 'John',
[role] => 'author',
),
[1] => array(
[name] => 'Gail',
[role] => 'author',
),
[2] => array(
[name] => 'Beth',
[role] => 'illustrator',
),
)
I'm trying to use this information to construct a detailed byline, like:
Written by John and Gail. Designed by Beth.
I need to compare each role to the previous and next ones in order to:
Use a label before the first instance of each role
Separate multiple instances of the same role with a comma
Use "and" instead of a comma before the last instance of each role
I'm no PHP expert so I'm having a hard time figuring out how to approach this! I have a function to output the right label depending on the role, but it's the comparisons I can't seem to figure out. I've considered foreach and while loops, but neither seems up to the job. I've never used a for loop so I don't know if it applies.
Some additional background:
I'm working with WordPress and the Advanced Custom Fields plugin.
$contributors is the value of an ACF Repeater field, where name and role are subfields. (I've simplified the names to make things easier.)
You can group the array per role and use array_pop to remove the element. implode the remaining array elements and just append the popped value.
$contributors = array(
array(
"name" => 'John',
"role" => 'author',
),
array(
"name" => 'Gail',
"role" => 'author',
),
array(
"name" => 'Jose',
"role" => 'author',
),
array(
"name" => 'Thomas',
"role" => 'author',
),
array(
"name" => 'Beth',
"role" => 'illustrator',
),
array(
"name" => 'Mary',
"role" => 'producer',
),
array(
"name" => 'Criss',
"role" => 'producer',
),
);
//Grouped the names according to role
$grouped = array_reduce($contributors, function($c, $v) {
if ( !isset( $c[ $v['role'] ] ) ) $c[ $v['role'] ] = array();
$c[ $v['role'] ][] = $v['name'];
return $c;
}, array());
//Construct final Array
$final = array();
foreach( $grouped as $key => $group ) {
$last = array_pop( $group );
if ( count( $group ) == 0 ) $final[ $key ] = $last; /* One one name on the role, no need to do anything*/
else $final[ $key ] = implode( ", ", $group ) . " and " . $last;
}
echo "<pre>";
print_r( $final );
echo "</pre>";
This will result to:
Array
(
[author] => John, Gail, Jose and Thomas
[illustrator] => Beth
[producer] => Mary and Criss
)
You can now use it as
echo 'Written by ' . $final["author"] . '. Designed by ' . $final["illustrator"] . '. Produced by ' . $final["producer"];
And will result to:
Written by John, Gail, Jose and Thomas. Designed by Beth. Produced by
Mary and Criss
You can try like this -
$contributors = array(
array(
'name' => 'John',
'role' => 'author',
),
array(
'name' => 'Gail',
'role' => 'author',
),
array(
'name' => 'Ali',
'role' => 'author',
),
array(
'name' => 'Beth',
'role' => 'illustrator',
)
);
#This function prepare array to expected String
function PrepareArray($data){
$combined = '';
if (count($data)>1) {
$last = array_slice($data, -1);
$first = join(', ', array_slice($data, 0, -1));
$both = array_filter(array_merge(array($first), $last), 'strlen');
$combined = join(' and ', $both);
}else{
$combined = implode('', $data);
}
return $combined;
}
$authors = array();
$designers = array();
foreach ($contributors as $key => $value) {
if ($value['role']=='author') {
$authors[] = $value['name']; #Keep Authors name in Array
}else if ($value['role']=='illustrator') {
$designers[] = $value['name']; #Keep Designers name in Array
}
}
$authors = PrepareArray($authors);
$designers = PrepareArray($designers);
echo "Written by {$authors}. Designed by {$designers}.";
Output :
Written by John, Gail and Ali. Designed by Beth.
Try below code:
<?php
$contributors = array(
0 => array(
'name' => 'John',
'role' => 'author',
),
1 => array(
'name' => 'Gail',
'role' => 'author',
),
2 => array(
'name' => 'Beth',
'role' => 'illustrator',
),
3 => array(
'name' => 'Albert',
'role' => 'author',
),
);
$labels = ['author'=>'Written by', 'illustrator'=>'Designed by', 'producer'=>'Produced by'];
$new_contributors = [];
foreach($contributors as $cont){
$new_contributors[$cont['role']][] = $cont['name'];
}
$str = '';
foreach($labels as $role=>$label){
if(isset($new_contributors[$role]) && is_array($new_contributors[$role])){
$str .= ' '.$label.' ';
foreach($new_contributors[$role] as $key=>$new_contributor){
$count = count($new_contributors[$role]);
if(($count - $key) == 1 ){
$str .= ' and ';
$str .= $new_contributor;
}else if(($count - $key) == 2){
$str .= $new_contributor;
}else{
$str .= $new_contributor.', ';
}
}
}
}
echo $str;
I have a simple php array for location postcode and their name. I want compress 'code' by 'name'. This code from WooCommerce database zones.
$new_arr = [
[
'name' => 'Jambi Selatan',
'code' => '36139',
'code_name' => '36139 - Jambi Selatan'
],
[
'name' => 'Jambi Selatan',
'code' => '36137',
'code_name' => '36137 - Jambi Selatan'
],
[
'name' => 'Bagan Pete',
'code' => '36129',
'code_name' => '36129 - Bagan Pete'
],
[
'name' => 'Bagan Pete',
'code' => '36127',
'code_name' => '36127 - Bagan Pete'
]
];
I want get final result combined by 'name' and 'code' like this: i try array_unique method but not working.
Array (
[0] => Array
(
[name] => Jambi Selatan
[code] => 36139, 36137
[code_name] => 36139, 36139 - Jambi Selatan
)
[1] => Array
(
[name] => Bagan Pete
[code] => 36127, 36129
[code_name] => 36127, 36129 - Bagan Pete
)
)
I try this method, but not fix at 'code_name'
$out = array();
foreach ($new_arr as $key => $value){
if (array_key_exists($value['name'], $out)){
$out[$value['name']]['code'] .= ', '.$value['code'];
} else {
$out[$value['name']] = array(
'name' => $value['name'],
'code' => $value['code'],
'code_name' => $value['code'] . ' - ' . $value['name']
);
}
}
$out = array_values($out);
print_r($out);
You have to check duplicate name by in_array and update exist array value .If not exist insert that value to $out array .
$out = array();
foreach($new_arr as $k=>$v) {
//empty array state
if(count($out) == 0) {
$out[] = $v;
continue;
}
foreach ($out as $key => $value) {
if(in_array($v["name"],$value)) {
$out[$key]["code"] .= ",".$v["code"];
//for the code_name output as OP described
$nn = explode("-", $value["code_name"]);
$l = count($nn) - 1;
unset($nn[$l]);
$out[$key]["code_name"] = implode($nn).",".$v["code_name"];
break;
} else {
if((count($out)-1) == $key) {
$out[] = $v;
}
}
}
}
var_dump($out);
For someone have problem like me, this method for fix it:
$out = array();
foreach ($new_arr as $key => $value){
if (array_key_exists($value['name'], $out)){
$out[$value['name']]['code'] .= ', '.$value['code'];
$out[$value['name']]['code_name'] .= ', '.$value['code'] . ' - ' . $value['name'];
} else {
$out[$value['name']] = array(
'name' => $value['name'],
'code' => $value['code'],
'code_name' => $value['code']
);
}
}
$out = array_values($out);
print_r($out);
Final result;
Array
(
[0] => Array
(
[name] => Jambi Selatan
[code] => 36139, 36137
[code_name] => 36139, 36137 - Jambi Selatan
)
[1] => Array
(
[name] => Bagan Pete
[code] => 36129, 36127
[code_name] => 36129, 36127 - Bagan Pete
)
)
Please try below one as another approach:
<?php
$arr = Array (
Array
(
'name' => 'Jambi Selatan',
'code' => '36139',
'code_name' => '36139 - Jambi Selatan'
),
Array
(
'name' => 'Jambi Selatan',
'code' => '36137',
'code_name' => '36137 - Jambi Selatan'
),
Array
(
'name' => 'Bagan Pete',
'code' => '36129',
'code_name' => '36129 - Bagan Pete'
),
Array
(
'name' => 'Bagan Pete',
'code' => '36127',
'code_name' => '36127 - Bagan Pete'
)
);
$newarr = array();
$finalArr = array();
foreach($arr as $aa) {
$newarr[$aa['name']][] = $aa;
}
foreach($newarr as $kk => $bb) {
foreach($bb as $cc) {
$finalArr[$kk]['name'] = $cc['name'];
if(isset($finalArr[$kk]['code'])) {
$finalArr[$kk]['code'] = $finalArr[$kk]['code'].','.$cc['code'];
} else {
$finalArr[$kk]['code'] = $cc['code'];
}
if(isset($finalArr[$kk]['code_name'])) {
$finalArr[$kk]['code_name'] = $finalArr[$kk]['code_name'].','.$cc['code_name'];
} else {
$finalArr[$kk]['code_name'] = $cc['code_name'];
}
}
}
echo "<pre>";
print_r($finalArr);
echo "</pre>";
?>
Definitely avoid any suggestions that use more than one loop to group and concatenate the data.
I do endorse #Opsional's snippet. An alternative approach is to push reference variables into the result array, then only concatenate comma-separated values to the appropriate reference variable.
Code: (Demo)
$result = [];
foreach ($arr as $row) {
if (!isset($ref[$row['name']])) {
$ref[$row['name']] = $row;
$result[] = &$ref[$row['name']];
} else {
$ref[$row['name']]['code'] .= ', ' . $row['code'];
$ref[$row['name']]['code_name'] .= ', ' . $row['code_name'];
}
}
var_export($result);
For any purist developers that insist on destroying references, call unset($ref) after the loop.
Here is a streamlined version of #Opsional's snippet: (Demo)
$result = [];
foreach ($arr as $row) {
if (!isset($result[$row['name']])) {
$result[$row['name']] = $row;
} else {
$result[$row['name']]['code'] .= ', ' . $row['code'];
$result[$row['name']]['code_name'] .= ', ' . $row['code_name'];
}
}
var_export(array_values($result));
I'm seem to be stuck on something..
What I'm trying to do: with the following sample data I'm trying to show the data first in category and then show the data in the subcategory.
Sample Data:
array('category'=> 'America',
'sub-category'=> 'Illinois',
'name'=>'John Doe');
array('category'=>'America',
'sub-category'=>'Wisconsin',
'name'=>'Jane Doe');
Basically like this:
America
Illinois
John Doe
Wisconsin
Jane Doe
I can do the category by using the following code:
foreach ($total_states as $key => $states) {
$states_category[$states['CATEGORY']]['category'] = $states['CATEGORY'];
$statest_category[$states['CATEGORY']]['name'][] = $states;
}
How can I break it down by sub-categories using that for loop?
I tested and come up with this code:
<?php
$datas = [
[
'category' => 'America',
'sub-category' => 'Illinois',
'name' => 'John Doe'
],
[
'category' => 'America',
'sub-category' => 'State',
'name' => 'John Doedf'
],
[
'category' => 'America',
'sub-category' => 'State',
'name' => 'ghghjgj Doe'
],
];
$newArray = [];
foreach($datas as $d)
$newArray[$d['category']][$d['sub-category']][] = $d['name'];
foreach($newArray as $country => $city) {
echo $country. '<br>';
foreach($city as $subcity => $users) {
echo "\t $subcity <br>";
foreach($users as $u)
echo "\t\t $u <br>";
}
}
Give a try to this:
Initial data:
$info = [
['category' => 'America',
'sub-category' => 'Illinois',
'name' => 'John Doe'],
['category' => 'America',
'sub-category' => 'Wisconsin',
'name' => 'Jane Doe']];
Foreach:
foreach ( $info as $array ){
foreach ( $array as $key => $value){
switch ( $key ){
case 'category' : {
echo $value . '<br>';
break;
}
case 'sub-category' : {
echo " " . $value . '<br>';
break;
}
case 'name' : {
echo " " . $value . '<br>';
break;
}
}
}
}
I have array with this format:
$components = [
[
'name' => 'ADIPIC ACID',
'cas' => '123',
'einecs' => '321'
],
[
'name' => 'ADIPIC ACID/DIMETHY- LAMINOHYDROXY- PROPYL DIETHYLENE- TRIAMINE COPOLYMER',
'cas' => '456',
'einecs' => '654'
]
]
I need to find each name which has a / character, break it and create a new entry in the $components array with cas and einecs being empty string.
Also the first part of the name will have cas and einecs values from the original entry.
Expected array:
$components = [
[
'name' => 'ADIPIC ACID',
'cas' => '123',
'einecs' => '321'
],
[
'name' => 'ADIPIC ACID',
'cas' => '456',
'einecs' => '654'
],[
'name' => 'DIMETHY- LAMINOHYDROXY- PROPYL DIETHYLENE- TRIAMINE COPOLYMER',
'cas' => '',
'einecs' => ''
]
]
How can I do this?
Quite crude I admit and it doesn't account for multiple / characters in a value but it does return the result expected.
foreach( $components as $index=> $arr ){
foreach( $arr as $key => $value ){
if( $key=='name' && strstr( $value, '/' ) ){
list($pre,$post)=explode('/',$value);
$components[$index][$key]=$pre;
$components[]=array('name'=>$post,'cas'=>'','einecs'=>'');
}
}
}
<?php
$components = [
[
'name' => 'ADIPIC ACID',
'cas' => '123',
'einecs' => '321'
],
[
'name' => 'ADIPIC ACID/DIMETHY- LAMINOHYDROXY- PROPYL DIETHYLENE- TRIAMINE COPOLYMER',
'cas' => '456',
'einecs' => '654'
]
];
$new = [];
foreach ($components as &$component) {
if ($items = explode('/', $component['name'])) {
$component['name'] = array_shift($items);
$new = array_merge($new, $items);
}
}
foreach ($new as $item) {
$components[] = ['name' => $item, 'cas' => '', 'einecs' => ''];
}
var_dump($components);
I would try something like this where I use the explode function using the '/' character on the name of each component. Then I'd create a new array of all the new components taking the values of the component being evaluated.
$newComponents = array();
foreach($components as $component) {
foreach(explode('/', $component['name']) as $newComponentName) {
$newComponents[] = array('name' =>$newComponentName,
'cas' => $component['cas'],
'einecs' => $component['einecs']);
}
}
foreach($components as $component)
{
if(strpos($component["name"],"/") !== false){
$temp = explode("/",$component["name"]);
$components[] = new array("name"=>$temp[1], "cas"=>"", "einecs"=>"");
}
}