In a multidimensional array, I'm trying to select all descendant arrays with a certain key, no matter what their parent arrays are. I know the following syntax doesn't work, but hopefully it will help illustrate what I'm trying to accomplish:
<?php
foreach ($array[*][*]['descendant'] as $descendent) {
// do stuff
}
?>
Similarly, I need to figure out whether sibling arrays do not contain this array key. Something like this (again, I know the syntax is horribly wrong):
<?php
foreach ($array[*][*]['descendant'] < 1 as $descendent) {
// do stuff
}
?>
If there are always 3-dimensional array, you can use nested loop:
foreach($array as $lv1) {
foreach($lv1 as $lv2) {
foreach($lv2['descendant'] as $descendent) {
// do stuff
}
}
}
If you want to support unlimited number of dimension, you can use this ugly code
function drill($arr) {
if (isset($arr) && is_array($arr)) {
foreach($arr as $key => $value) {
if ($key == 'descendant') {
foreach($value as $descendent) {
// do stuff here
}
} else {
drill($value);
}
}
}
}
drill($array);
Related
So I have a function that currently has a foreach and it works amazing, but I'm being forced to change it to a while loop:
PLEASE NOTE: The developers at my company don't want to use the foreach and they think that a while loop would be more efficient, but I'm not understanding how that would be executed, so I need some help.
So I have the following function ($post_blocks is an array of arrays):
public function parse_block_data(string $block_name, string $selector, $post_id)
{
if (!has_blocks($post_id)) {
return false;
}
$post_blocks = parse_blocks(get_the_content('', false, $post_id));
foreach ($post_blocks as $block) {
if ($block_name != $block['blockName']) {
continue;
}
if (!isset($block['attrs']['id'])) {
return false;
}
if (isset($block['attrs']['data'][$selector])) {
return $block['attrs']['data'][$selector];
} else {
break;
}
}
return false;
}
It uses the parameters to build up an array as shown below:
Output
So I started building a while loop inside the function, but I'm clueless on how to achieve it without using a foreach or if it's even possible, so I replaced the foreach with:
// I get the 9 counts of $post_blocks correctly.
$block = 0;
while ($block < count($post_blocks))
// If the $block_name doesn't match `blockName` value inside the multi-dimensional array, then continue iterating until the end and then return false.
// If ['attrs']['id'] is not set, return false.
// At last, if we have a blockName and a ID and the selector is set, return ['attrs']['data'][$selector]
}
All help will be appreciated! It makes no sense to me, but if someone can assist, I'd be forever grateful!
It's basically the same as your foreach loop, you just set the iteration variable by indexing the array, and increment the index manually.
$block_num = 0;
while ($block_num < count($post_blocks)) {
$block = $post_blocks[$block_num];
if ($block_name == $block['blockName']) {
if (!isset($block['attrs']['id'])) {
return false;
}
if (isset($block['attrs']['data'][$selector])) {
return $block['attrs']['data'][$selector];
} else {
break;
}
}
$block_num++;
}
I'm not sure why your colleagues think this is preferable.
If there's a company coding style they want you to follow, why don't you ask them what it should be?
I am looping thru two Arrays. $wooProducts and $data. Both arrays look the same and contain WooCommerce products.
My goal is to loop thru $wooProducts and remove the matched product from $data.
Everything work except the unset() part. Any idea how I can make it work? I tried this as well: unset($data[$matchedProduct]);
// Find function
function find($array, $key) {
foreach ($array as $product) {
if ($product["Name"] == $key) {
return $product;
}
}
}
$updateProducts = [];
// Check if product already exist
foreach ($wooProducts as $wooProduct) {
$matchedProduct = find($data, $wooProduct->post_title);
if ($matchedProduct) {
array_push($updateProducts, $matchedProduct);
unset($data[$wooProduct]); // <---- Not working
}
}
You can use array_search() to find the index and then you can use unset.
array_search($wooProduct->post_title, $data);
I have the following code to iterate through json array and change the value in the array.
<?php
$json='[{"type":"dropdown","label":"Is the property tenanted ?","req":0,"choices":[{"label":"Yes","sel":0,"notification":0,"subOptions":[{"NoteLabel":"Real Estate Agency ?","NoteValue":"","reqNote":"1"},{"NoteLabel":"Agents Mobile Number:","NoteValue":"","reqNote":"1"},{"NoteLabel":"Agents Email:","NoteValue":"","reqNote":"0"},{"PhotoLabel":"Attach a photo","PhotoValues":"","reqPhoto":"1"},{"NoteLabel":"Tenants Contact Number:","NoteValue":"","reqNote":"0"}]},{"label":"No","sel":1,"notification":0,"subOptions":[{"NoteLabel":"Clients Contact Number:","NoteValue":"","reqNote":"1"},{"PhotoLabel":"Attach a photo","PhotoValues":"","reqPhoto":"1"}]},{"label":"N\/A","sel":0,"notification":0,"subOptions":[]}]}]';
echo $json."<br/>";
echo "<br/><br/><br/>****************<br/><br/><br/>";
$json=json_decode($json,true);
foreach($json as $kSub => $vSub)
{
if( in_array($vSub['type'], ["dropdown"]))
{
if($vSub['label']=="Is the property tenanted ?")
{
$choices=&$vSub['choices'];
foreach($choices as $keyChoice=>&$valChoice)
{
if($valChoice['label']=="Yes")
{
$subOptions=&$valChoice['subOptions'];
foreach($subOptions as $kop=>&$Opval)
{
foreach($Opval as $kn=>&$vn)
{
if($kn=="NoteLabel")
{
if($vn=="Real Estate Agency ?")
{
$subOptions[$kop]['NoteValue']="DOMAIN";
}
}
}
}
}
}
}
}
}
echo json_encode($json)."<br/>";
I want to change the NoteValue inside subOptions array if the conditions are met. I am not sure whether I am doing it right or not, but the value is not changing. Please help me to sort out what I am doing wrong! I was also wondering whether I can reduce the number of code lines to get the result?
You need to use &vSub to make it a reference variable.
You can shorten the code by getting rid of the last loop, and just access the NoteLabel index directly. You can also combine the first two tests with &&. And you don't need any of the index variables in your foreach loops.
foreach($json as &$vSub)
{
if($vSub['type'] == "dropdown" && $vSub['label']=="Is the property tenanted ?")
{
$choices=&$vSub['choices'];
foreach($choices as &$valChoice)
{
if($valChoice['label']=="Yes")
{
$subOptions=&$valChoice['subOptions'];
foreach($subOptions as &$Opval)
{
if (isset($Opval['NoteLabel']) && $Opval['NoteLabel'] == "Real Estate Agency ?")
{
$Opval['NoteValue']="DOMAIN";
}
}
}
}
}
}
I'm trying to simplify a piece of PHP code looking like this :
public function gather($parameters, $infos)
{
$gathered = [];
$number = false;
foreach ($infos as $info) {
foreach ($parameters as $parameter) {
if (strlen($parameter['number'])) {
$this->mark($parameter['number'], $info, $parameter, $gathered); // $gathered is passed by reference
$number = true;
continue;
}
if (strlen($parameter['default'])) {
$this->mark($parameter['default'], $info, $parameter, $gathered); // $gathered is passed by reference
continue;
}
if ($config['smth']) {
doSomething(...);
}
}
}
if (number > 0) {
doSomething(...);
}
return $gathered;
}
Here are the problems I have :
These nested foreaches are really ugly and I'd love to the second one in the other function. But it uses variables that are created and used outside. I already used references with $gathered even if it's not really good.
The conditions of all ifs are different and are using different variables, do you know any way to generalize a case like this?
I am ok to rewrite big parts of the functions, so I'd be happy to hear other design ideas too.
[EDIT] The mark functions add elements to $gathered with some conditions and transformations.
[EDIT] Added more details.
I have this code to add new elements to a multidimension array:
$this->shopcart[] = array(productID => $productID, items => $items);
So how do i remove an element from this array? I tried this code, but its not working:
public function RemoveItem($item)
{
foreach($this->shopcart as $key)
{
if($key['productID'] == $item)
{
unset($this->shopcart[$key]);
}
}
}
I get this error:
Warning: Illegal offset type in unset in C:\xampplite\htdocs\katrinelund\classes\TillRepository.php on line 50
public function RemoveItem($item)
{
foreach($this->shopcart as $i => $key)
{
if($key['productID'] == $item)
{
unset($this->shopcart[$i]);
break;
}
}
}
That should do the trick.
Update
There is also an alternative way:
if ( false !== $key = array_search($item, $this->shopcart) )
{
unset($this->shopcart[$key];
}
You're not enumerating over indices, but values there, to unset an array index, you have to unset it by index, not by value.
Also, If your array index is actually the productID you can eliminate the loop altogether:
public function RemoveItem($productID)
{
if (isset($this->shopcart[$productID]))
{
unset($this->shopcart[$productID]);
}
}
Your example doesn't show how you are adding items to $this->shopcart, but this may or may not be an option for you depending on the needs of your project. (i.e. not if you need to have seperate instances of the same productid in the cart).