I have a multidimensional array. If it contains less than a threshold $threshold = 1000 bits/bytes/anything of data in total, including it's keys, I want to fetch more content.
What is the cheapest way, performance/memory wise, to get an approximate of the array size?
Right now, I use strlen(serialize($array)). Updated as per the comments:
$threshold = 1000;
$myArray = array(
'size' => 0,
'items' => array(
['id' => 1, 'content' => 'Lorem ipsum'],
['id' => 2, 'content' => 'Dolor sit'],
['id' => 3, 'content' => 'Amet']
)
);
while($myArray['size'] < $threshold)
{
echo "Array size is below threshold.<br/>";
addStuffToArray($myArray);
}
function addStuffToArray(&$arr)
{
echo "Adding stuff to array.<br/>";
$newArrayItem = array(
'id' => rand(0, 10000),
'content' => rand(999999, 999999)
);
$arr['size'] += strlen(serialize($newArrayItem));
$arr['items'][] = $newArrayItem;
}
PHPFiddle here.
You could always just count:
$count = array_map('count', $myArray);
This will give you an array with the count of all the sub-arrays.
However, the way you have done it is not bad.
Related
Hi guys I am a beginner with PHP and want the best way in terms of performance to convert this array:
$old = array(
20 =>
array(
'name' => 'Heels',
'path' => '1/2/10/15/20',
),
15 =>
array(
'name' => 'Sandals',
'path' => '1/2/80/96/15',
),
10 =>
array(
'name' => 'Trainers',
'path' => '1/2/80/96/10',
),
);
To this:
$new = array(
20 =>
array(
'value' => 20,
'label' => 'Trainers > Sandals > Heels',
),
);
There is going to be loads of records surely exploding the paths and mapping them with the ids is going to slow it down in terms of performance just wondering whether there is a more efficient way if possible thanks.
If I understand correctly, you're trying to get the latest path relevant to each category and output it as a breadcrumb.
You can first sort the keys (ids) and then loop through the array creating the breadcrumb.
arsort($paths); # This gives the desired output in OP but makes more sense to use krsort() to sort DESC not ASC
$breadcrumb = (object) array (
'value' => array_keys($paths)[count($paths) - 1], # Get the highest id - if using krsort() use array_keys($paths)[0]
'labels' => implode(' > ', array_column($paths, 'name'));
);
# Update derived from The fourth bird's answer which skips the need for the foreach().
# Concept is to build an array of the labels to then make look pretty with the > effect
Here is a demo.
Output:
object (stdClass) (2) {
["value"] => int(20)
["labels"] => string(26) "Trainers > Sandals > Heels"
}
Another option could be to first create a mapper of the keys and the names. Then you could take the key from the mapper to create the path:
$result = [];
$mapper = array_combine(array_keys($old), array_column($old, 'name'));
foreach ($old as $key => $value) {
$path = implode(' > ', array_map(function($x) use ($mapper) {
return $mapper[(int)$x];
}, explode('/', $value['path'])));
$result[$key] = ['value' => $key,'label' => $path];
}
print_r($result);
Php demo
This is the hardcoded way, but i think you need to give a bit more information to get a dynamic solution.
<?php
$old = array(
20 =>
array(
'name' => 'Heels',
'path' => '1/2/10/15/20',
),
15 =>
array(
'name' => 'Sandals',
'path' => '1/2/80/96/15',
),
10 =>
array(
'name' => 'Trainers',
'path' => '1/2/80/96/10',
),
);
ksort($old);
$breadcrumbs = [];
$currentKey = 0;
foreach ( $old as $itemKey => $item) {
$currentKey = $itemKey;
$breadcrumbs[] = $item;
}
$new = [$currentKey] = [
'value' => $currentKey,
'label' => implode(' > ', $breadcrumbs)
];
printf($new);
I have an array of arrays, as such
$statuses = array(
[0] => array('id'=>10, 'status' => 'active'),
[1] => array('id'=>11, 'status' => 'closed'),
[2] => array('id'=>12, 'status' => 'active'),
[3] => array('id'=>13, 'status' => 'stopped'),
)
I want to be able to make a new array of arrays and each of those sub arrays would contain the elements based on if they had the same status.
The trick here is, I do not want to do a case check based on hard coded status names as they can be random. I want to basically do a dynamic comparison, and say "if you are unique, then create a new array and stick yourself in there, if an array already exists with the same status than stick me in there instead". A sample result could look something like this.
Ive really had a challenge with this because the only way I can think to do it is check every single element against every other single element, and if unique than create a new array. This gets out of control fast if the original array is larger than 100. There must be some built in functions that can make this efficient.
<?php
$sortedArray = array(
['active'] => array(
array(
'id' => 10,
'status' => 'active'
),
array(
'id' => 12,
'status' => 'active'
)
),
['closed'] => array(
array(
'id' => 11,
'status' => 'active'
)
),
['stopped'] => array(
array(
'id' => 13,
'status' => 'active'
)
),
)
$SortedArray = array();
$SortedArray['active'] = array();
$SortedArray['closed'] = array();
$SortedArray['stopped'] = array();
foreach($statuses as $Curr) {
if ($Curr['status'] == 'active') { $SortedArray['active'][] = $Curr; }
if ($Curr['status'] == 'closed') { $SortedArray['closed'][] = $Curr; }
if ($Curr['status'] == 'stopped') { $SortedArray['stopped'][] = $Curr; }
}
You can also do it with functional way though it's pretty the same like Marc said.
$sorted = array_reduce($statuses, function($carry, $status) {
$carry[$status['status']][] = $status;
return $carry;
}, []);
so I'm trying to write a method that will merge all the arrays with a certain key value, but the problem I'm running into is that when I try and unset the array, so that there are not duplicate results it skips over several things, which is confusing me. so any advice on how I can improve this method would be greatly appreciated. the other question I have.. is there a way to check if each of these arrays have all 4 keys that I'm looking for.
'Release Date' =>
'Spreadsheet and Flyer Month' =>
'Advertise in Monthly Update' =>
'Feature in Catalog' =>
so what I'm doing is merging arrays with the same id in the db, so I don't have to do some really nasty SQL querys, but I'm wondering if there's a way of making sure that all 4 of these keys will be in every result... and if there is a value associated with one or however many.. my method will add the value to its key, and if there is no value associated with the key it will just make a empty string.
protected function array_with_same_val($array, $key) {
for($i = 0; $i < count($array); $i++) {
for($j = 1; $j < count($array); $j++) {
if(isset($array[$j]) && isset($array[$i]) && $array[$i][$key]==$array[$j][$key]) {
$temp = array_merge($array[$i], $array[$j]);
$array[$i] = $temp;
//unset($array[$j]);
}
}
}
return $array;
}
Here is a sample of my array (there will be a lot more values, this is just to give an idea):
'0' => array
(
'Release Date' => 'September 1, 2013',
'cp_id' => '112960'
),
'1' => array
(
'Spreadsheet and Flyer Month' => 'September 1, 2013',
'cp_id' => '112960'
),
'2' => array
(
'Advertise in Monthly Update' => 'September 1, 2013',
'cp_id' => '112960'
),
'3' => array
(
'Release Date' => 'September 1, 2013',
'cp_id' => '109141'
),
);
any help on this would be greatly appreciated.
Try this ($input is the array you provided above) ...
$output = array();
$requiredKeys = array('Release Date' => '', 'Spreadsheet and Flyer Month' => '', 'Advertise in Monthly Update' => '', 'Feature in Catalog' => '');
foreach ($input as $item) {
if (array_key_exists($item['cp_id'], $output)) {
$output[$item['cp_id']] = array_merge($output[$item['cp_id']], $item);
} else {
$output[$item['cp_id']] = array_merge($requiredKeys, $item);
}
}
$output = array_values($output);
The array_values call at the bottom is just to remove the string keys from the array.
I have a multidimensional array which I am looping through using a foreach loop.
I have then need to check whether any of those arrays have the key of 'parent_page' and the same value of any other arrays, such as:
$arrMulti = array(array(
'page_id' => 1,
'page_parent' => 28,
'page_title' => 'Testing'
), array(
'page_id' => 2,
'page_parent' => 30,
'page_title' => 'A seperate page'
), array(
'page_id' => 3,
'page_parent' => 28,
'page_title' => 'Testing Sub Page'
));
So $arrMulti[0]['page_parent'] would match with $arrMulti[2]['page_parent'], so I need to then create a new array using those, something like this:
$arrParentIDs = array( 'parent_id' => array(
1,
3
));
Sorry for the poor explanation, but do you have any idea on how to do this?
Thanks!
$parentIds = array();
foreach($arrMulti as $temp):
if(isset($temp['page_parent'] && !in_array($temp['page_parent'], $parentIds)){
$parentIds[] = $temp['page_parent'];
}
endforeach;
var_dump($parentIds);//to show the contents
Try something like this..
foreach($arrMulti as $array) {
foreach($array as $key=>$val) {
//your statement/condition
}
}
I have a multi-dimensional array that looks like this:
The base array is indexed based on category ids from my catalog.
$cat[category_id]
Each base array has three underlying elements:
['parent_id']
['sort_order']
['name']
I want to create a function that allows us to create a list of category_id's and names for a given parent_category_id in the correct sort order. Is this possible? Technically it is the same information, but the array is constructed in a weird way to extract that information.
Here is an example definition for the array:
$cat = array();
$cat[32]['parent_id']= 0;
$cat[32]['sort_order']= 1;
$cat[32]['name']= 'my-category-name1';
$cat[45]['parent_id']= 0;
$cat[45]['sort_order']= 0;
$cat[45]['name']= 'my-category-name2';
$cat[2]['parent_id']= 0;
$cat[2]['sort_order']= 2;
$cat[2]['name'] = "my-category-name3";
$cat[3]['parent_id']= 2;
$cat[3]['sort_order']= 1;
$cat[3]['name'] = "my-category-name4";
$cat[6]['parent_id']= 2;
$cat[6]['sort_order']= 0;
$cat[6]['name'] = "my-category-name5";
Assuming it's something of this sort:
$ary = Array(
0 => Array(
'parent_category_id' => null,
'sort_order' => 0,
'name' => 'my-category-name0'
),
1 => Array(
'parent_category_id' => 0,
'sort_order' => 1,
'name' => 'my-category-name1'
),
2 => Array(
'parent_category_id' => 0,
'sort_order' => 2,
'name' => 'my-category-name2'
),
3 => Array(
'parent_category_id' => null,
'sort_order' => 0,
'name' => 'my-category-name3'
),
4 => Array(
'parent_category_id' => 3,
'sort_order' => 0,
'name' => 'my-category-name4'
)
);
You can use a combination of a foreach and usort to achieve what you're going for.
// #array: the array you're searchign through
// #parent_id: the parent id you're filtering by
function getFromParent($array, $parent_id){
$result = Array();
foreach ($array as $category_id => $entry){
if ($entry['parent_category_id']===$parent_id)
$result[$category_id] = $entry;
}
usort($result,create_function('$a,$b','return ($a["sort_order"]>$b["sort_order"]?1:($b["sort_order"]<$a["sort_order"]?-1:0));'));
return $result;
}
var_export(getFromParent($ary,0));
EDIT Sorry, fixed some syntax errors. Tested, and works (at least to result in what I was intending)
EDITv2 Here's the raw output from the above:
array (
0 =>
array (
'parent_category_id' => 0,
'sort_order' => 1,
'name' => 'my-category-name1',
),
1 =>
array (
'parent_category_id' => 0,
'sort_order' => 2,
'name' => 'my-category-name2',
),
)
(Used var_export just for you #FelixKling)
EDITv3 I've updated my answer to go along with the OP's update. I also now make it retain the original "category_id" values in the result array.
First you create an empty array, it will be used to store your result.
$result = array();
You need to iterate through your initial array, you can use foreach().
Then, given your parent_category_id simply use an if statement to check whether it's the given id or not.
If it is, just construct and push your result to your $result array.
Use any of the sort functions you like
Use the magic return $result;
You're done.
function returnSortedParents($categories, $target_parent){
$new_list = array();
foreach($categories as $index => $array){
//FIND ONLY THE ELEMENTS MATCHING THE TARGET PARENT ID
if($array['parent_category_id']==$target_parent){
$new_list[$index = $array['sort_order'];
}
return asort($new_list); //SORT BASED ON THE VALUES, WHICH IS THE SORTING ORDER
}