Hi I have an array that contains two arrays that has the following structure:
categories [
"lvl0" => array:2 [
0 => "Cleaning"
1 => "Bread"
]
"lvl1" => array:2 [
0 => null
1 => "Bread > rolls"
]
]
I would like to remove any records of NULL from the 'lvl1' array but have not been able to find the correct method to do this.
I have tried:
array_filter($categories['lvl1'])
But this also removes all records associated to lvl1 and not just the NULL ones.
Any help would be greatly appreciated.
Thanks
array_filter() takes a callback as the second argument. If you don't provide it, it returns only records that aren't equal to boolean false. You can provide a simple callback that removes empty values.
array_filter() also uses a copy of your array (rather than a reference), so you need to use the return value.
For instance:
$categories = [
"lvl0" => [
"Cleaning",
"Bread"
],
"lvl1" => [
null,
"Bread > rolls"
]
];
$lvl1 = array_filter($categories['lvl1'], function($value) {
return !empty($value);
});
var_dump($lvl1);
That will return:
array(1) {
[1] =>
string(13) "Bread > rolls"
}
I was having the same issue on my last working day.Generally for associative array array_filter() needs the array key to filter out null, false etc values. But this small function help me to filter out NULL values without knowing the associative array key. Hope this will also help you, https://eval.in/881229
Code:
function array_filter_recursive($input)
{
foreach ($input as &$value)
{
if (is_array($value))
{
$value = array_filter_recursive($value);
}
}
return array_filter($input);
}
$categories = [
"lvl0" => [
"Cleaning",
"Bread"
],
"lvl1" => [
null,
"Bread > rolls"
]
];
$result = array_filter_recursive($categories);
print '<pre>';
print_r($result);
print '</pre>';
Output:
(
[lvl0] => Array
(
[0] => Cleaning
[1] => Bread
)
[lvl1] => Array
(
[1] => Bread > rolls
)
)
Ref: http://php.net/manual/en/function.array-filter.php#87581
Robbie Averill who commented on my post with the following solved the issue:
$categories['lvl1'] = array_filter($categories['lvl1']);
Related
<?php
$all_stock_data = [
"kit_38320" => [
"law" => [
1724 => [
'id' => 320044,
'reserved' => 4
]
]
]
];
foreach($all_stock_data["kit_38320"]["law"] ?? [] as &$section_stock){
$section_stock['reserved'] += 1;
}
echo "<pre>";
print_r($all_stock_data);
if a use "?? []" in foreach reserved count is not increase.
who can explain this?
if(empty($all_stock_data["kit_38320"]["law"])){
$all_stock_data["kit_38320"]["law"] = [];
}
foreach($all_stock_data["kit_38320"]["law"] as &$section_stock){
$section_stock['reserved'] += 1;
}
Thank u for answers. I think its better way
(not sure of the terminology but) It is effectively creating a copy of the value as
$all_stock_data["kit_38320"]["law"] ?? []
is an expression, so the foreach is operating over the result of the expression and not the $all_stock_data array.
If you add some extra displays to show the values...
foreach($all_stock_data["kit_38320"]["law"] ??[] as &$section_stock){
print_r($section_stock);
$section_stock['reserved'] += 1;
print_r($section_stock);
}
you get the value is being updated
Array
(
[id] => 320044
[reserved] => 4
)
Array
(
[id] => 320044
[reserved] => 5
)
but this isn't in the $all_stock_data array.
With PHP 7.4, I have associative array with objets :
$array = [
1 => Class {
'id' => 1,
'call' => true,
},
5 => Class {
'id' => 5,
'call' => false,
},
7 => Class {
'id' => 7,
'call' => true,
},
]
I want to extract all the IDs if the call attribute === true.
After searching, I think I should use the array_map function.
$ids = array_map(function($e) {
if (true === $e->call) {
return $e->id;
}
}, $array);
// Return :
array(3) {
[1]=> 1
[5]=> NULL
[7]=> 7
}
But I have two problems with this:
I don't want NULL results
I don't wish to have the associative keys in in my new array. I want a new array ([0=>1, 1=>7])
I know I can do it with a foreach() but I find it interesting to do it with a single PHP function (array_walk or array_map ?)
Create an array which is the call value indexed by the id and then filter it. As the id is the index, then extract the keys for the ids...
$ids = array_keys(array_filter(array_column($array, "call", "id")));
print_r($ids));
Array
(
[0] => 1
[1] => 7
)
Although I think a foreach() is a much more straight forward method.
You probably want array_filter to filter out what you don't want, then you can extract the id:
$ids = array_column(array_filter($array, function($e) {
return $e->call === true;
}), 'id');
You can reduce the array with a callback that conditionally adds each item's id to the "carry" array.
$ids = array_reduce($array, fn($c, $i) => $i->call ? [...$c, $i->id] : $c, []);
I need to compare arrays, if element from first or second array has duplicates in another one I need to exclude it. I know it sound simply and I'm sure it is but i cant handle with that problem :(
So i have first array like this:
Array:3 [
6 => blog/something
4 => blog/somethingElse
5 => blog/else
]
Second array almost identical:
Array:3 [
1 => /blog
2 => /comments
3 => /posts
]
And the last array:
(integer on the left is id of elements in second array, in this example
comments and posts)
Array:2 [
0 => array:2 [
'page_id' => 2
'value' => noindex
]
1 => array:2 [
'page_id' => 3
'value' => noindex
]
]
So if I have element in array first or second which exist in array thrid too AND have value = noindex i need to exclude it.
I have tried do this by foreach recursive, by array_walk_recursive but I still can't get satisfied result
First get all the indices you need to exclude and then exclude them:
$excludeIndices = array_column(array_filter($array3, function ($entry) {
return $entry['value'] === 'noindex';
}), 'page_id');
$keepArray1 = array_diff_key($array1, array_flip($excludeIndices));
$keepArray2 = array_diff_key($array2, array_flip($excludeIndices));
Sandbox
You can filter using the first two arrays directly.
$result = array_filter($last, function($item) use ($first, $second) {
return !($item['value'] == 'noindex' &&
(isset($first[$item['page_id']]) || isset($second[$item['page_id']]))
);
});
I got the following array:
"task" : {
"author_id" : 150,
"created_at" : somedate,
"status_id" : 2,
"assignee_id" : 100,
"updated_at" : somedate_too
and I got 2 more associative arrays where I store names for IDs in the following way:
"100" => Mike,
"150" => Bob //etc..., the same for statuses
I need to check for the IDs in the first array and replace numbers with names for the corresponding arrays in the most effective way. I tried the following:
if(isset(task['status_id'])){$row = array_merge($row, [$status_ids[
task['status_id']]]);}else{$row = array_merge($row, '');}
if(isset(task['author_id'])){row = array_merge($row, [$users[// note the different array here
task['author_id']]]);}else{$row = array_merge($row, '');}
if(isset(task['assignee_id'])){$row = array_merge($row, [$users[
task['assignee_id']]]);}else{$row = array_merge($row, '');}
In my resulting array ($row) I cannot miss the index and replace it with another value. If there is no value in the first array, I need to insert an empty string to get the following, for example:
['in progress', '', 'Mike']
if there is no author_id in the first array. I believe there should be a better way to do it with foreach loop, but I cant find out how because for different fields I get the data from different arrays. I dont think a separate if clause for every field is the most suitable here.
Any help would be welcome. Thank You.
You could map your special keys to their array counterparts using references and use that mapping when populating $row, like this:
$users = [
"100" => "Mike",
"150" => "Bob",
];
$status_ids = [
1 => "Foo",
2 => "Bar",
];
// Define output format and array mapping
$mapping = [
"author_id" => &$users, // Mapped to $users array
"created_at" => null, // Not mapped, keep $task value
"status_id" => &$status_ids,
"assignee_id" => &$users,
"updated_at" => null,
];
$task = [
"author_id" => 150,
"created_at" => "Some date",
"status_id" => 2,
// "assignee_id" => 99999, // Oops, missing key/value => empty string in $row
"updated_at" => "Some other date",
];
foreach ($mapping as $key => $mappedArray) {
#$row[] = $mappedArray
? $mappedArray[$task[$key]] ?: ''
: $task[$key];
}
print_r($row);
Output:
Array
(
[0] => Bob
[1] => Some date
[2] => Bar
[3] =>
[4] => Some other date
)
It should work (I didn't try it, but it should give you the general idea):
<?php
$fields = array("author_id", "assignee_id", "status_id");
$aliases = array("users", "users", "status_ids");
foreach ($task as $key=>&$value) {
$alias = str_replace($fields, $aliases, ${$key});
if (is_array(${$alias}) {
$value = array_key_exists($value, ${$alias}) ? ${$alias}[$value] : "";
}
}
unset($value);
And then you can fill up your $row as you planned, directly from the $task array.
I need some help wrapping my head around a problem. I have an array filled with other arrays. I need to:
Loop through the entire array and build a new array called finalOptions
Each iteration of the loop will take a new SearchIndex and apply the other paramenters
i.e
SearchIndex => SportingGoods
MinPercentageOff => 50
MinimumPrice => 1
ItemPage => 1
Sort => salesrank
BrowseNode => 2342470011
THEN:
Final array should contain data like this
SearchIndex => SportingGoods
MinPercentageOff => 60
MinimumPrice => 100
ItemPage => 2
Sort => salesrank
BrowseNode => 3403201
Basically, I'm creating a new array and sending it to another method that will execute a call to an API and return a result, then doing it again until my array options are complete.
This might not be the way to go and I'm looking for suggestions/pseudo code on an approach. Here is the basics of what I have so far:
Starting with this code
$allOptions = array(
"SearchIndex" => array("SportingGoods", "Tools"),
"MinPercentageOff" => array("50", "60", "70"),
"MinimumPrice" => array("1", "100", "1000"),
"ItemPage" => array("1", "2"),
"Sort" => array("salesrank")
"BrowseNode" => array(
"SportingGoods" => array("2342470011", "3403201"),
"Tools" => array("511364")
)
)
$finalOptions = array();
foreach($allOptions as $options){
foreach($options["SearchIndex"] as $searchIndex){
$finalOptions[] = "SearchIndex" => $searchIndex[]
}
$this->itemSearch($finalOptions);
}
EDIT
The arrays will contain more values. i.e "ItemPage" => array("1", "2"), will have 1 - 10. The others will have more values as well.
From the given array it will produce 54 possible combinations as you described.
Also you need to make sure you have array in $allOptions['BrowseNode'] indexed as each value of $allOptions['SearchIndex']. Otherwise it will produce error.
Cartesian function from here.
$allOptions = [
"SearchIndex" => ["SportingGoods", "Tools"],
"MinPercentageOff" => ["50", "60", "70"],
"MinimumPrice" => ["1", "100", "1000"],
"ItemPage" => ["1", "2"],
"Sort" => ["salesrank"],
"BrowseNode" => ["SportingGoods" => ["2342470011", "3403201"], "Tools" => ["511364"] ] ];
$finalOptions = $allOptions; // copy our initial $allOptions array
unset($finalOptions['BrowseNode']); // deal with BrowseNode key later with custom iterator
$cartesian_product = cartesian($finalOptions); // find cartesian except BrowseNode
foreach($cartesian_product as $cartesian) // each member of cartesian product will iterate here
{
foreach($allOptions['BrowseNode'][$cartesian['SearchIndex']] as $possible)
/*
We have unset the BrowseNode, so need to refer original $allOptions array for BrowseNode,
In every cartesian product, we will get $cartesian['SearchIndex'] and it will contain either
'SportingGoods' or 'Tools' , so in our original array, look for 'BrowseNode' value, having key
same as $cartesian['SearchIndex'].
$allOptions['BrowseNode'][$cartesian['SearchIndex']] <---- is similar to below two lines
$key = $cartesian['SearchIndex'];
$allOptions['BrowseNode'][$key];
Finally iterate through $allOptions['BrowseNode'][$cartesian['SearchIndex']] will iterate as many times,
as many values there are
*/
{
$cartesian['BrowseNode'] = $possible; // assign the long waited key here to 'BrowseNode'
var_dump($cartesian); // here you can do $this->itemSearch($cartesian);
}
}
function cartesian($input) {
$input = array_filter($input);
/*
will renove any false values in input array,
in our array's case, it will do nothing.
*/
$result = [[]];
foreach ($input as $key => $values) {
$append = [];
foreach($result as $product) {
foreach($values as $item) {
$product [$key] = $item;
$append [] = $product;
}
}
$result = $append;
}
return $result;
}