I've searched stackoverflow and found many similar questions which where solved with array_slice, array_splice and the occasional array_merge, but none of these worked for me and I'm stumped. I must be doing something wrong, but can't figure out what exactly.
My problem:
I have a nested associative array representing a menu structure. It looks like this
$this->navigation_array=[
"CATEGORY_MAIN"=>[
"Page1"=>"page1.php",
"Page2"=>"page2.php",
"Page3"=>"page3.php",
"Page4"=>"page4.php"
],
"CATEGORY_NEW"=>[
"Page1"=>"page1_edit.php",
"Page2"=>"page2_edit.php",
"Page3"=>"page3_edit.php"
],
"CATEGORY_EMPTY1"=>[],
"CATEGORY_EMPTY2"=>[],
"SEARCH"=>[
"Page1"=>"page1_search.php",
"Page2"=>"page2_search.php",
"Page3"=>"page3_search.php"
],
"BACK"=>["Home"=>"index.php"]
];
Now I need a function to add a new category at a given position from either the beginning or the end of the navigation_array. So, either $MENU->category_add("test",2) or $MENU->category_add("test",-1)
What I tried so far fails, even though I tried several different approaches from here, here or here. The current, non-functional, iteration looks like this
public function category_add(string $category,int $position=0): bool{
if(array_key_exists($category,$this->navigation_array))return false;
if($position!=0){
$category_array=array($category=>[]);
array_splice($this->navigation_array,$position,0,$category_array);
}else $this->navigation_array[$category]=array(); //simply append if pos is 0
return true;
}
It does insert at the correct position when I call it with $MENU->category_add("test",2) or $MENU->category_add("test",-1) but what is inserted is [0] => Array ( ) instead of ["test"] => Array ( ).
The resulting navigation array thus looks like this:
Array ( [CATEGORY_MAIN] => Array ( [Page1] => page1.php [Page2] => page2.php [Page3] => page3.php [Page4] => page4.php ) [CATEGORY_NEW] => Array ( [Page1] => page1_edit.php [Page2] => page2_edit.php [Page3] => page3_edit.php ) [CATEGORY_EMPTY1] => Array ( ) [CATEGORY_EMPTY2] => Array ( ) [SEARCH] => Array ( [Page1] => page1_search.php [Page2] => page2_search.php [Page3] => page3_search.php ) [0] => Array ( ) [BACK] => Array ( [Home] => index.php ) )
But should look like
Array ( [CATEGORY_MAIN] => Array ( [Page1] => page1.php [Page2] => page2.php [Page3] => page3.php [Page4] => page4.php ) [CATEGORY_NEW] => Array ( [Page1] => page1_edit.php [Page2] => page2_edit.php [Page3] => page3_edit.php ) [CATEGORY_EMPTY1] => Array ( ) [CATEGORY_EMPTY2] => Array ( ) [SEARCH] => Array ( [Page1] => page1_search.php [Page2] => page2_search.php [Page3] => page3_search.php ) [test] => Array ( ) [BACK] => Array ( [Home] => index.php ) )
I know it's probably something pretty minor or silly that I'm overlooking, but I've stared at this so long, I'm obviously blind to it.
Could somebody be so kind and give me a hint?
Edit
So according to the php doc, ""Note: Keys in the replacement array are not preserved." array_splice does not work. But there must be another way to somehow achieve this, right?
Try this code, it has two functions category_add which is calling arrayInsert custom function, we can add a whole new category as well as insert new page inside of existing category.
<?php
$navigation_array = [
"CATEGORY_MAIN" => [
"Page1" => "page1.php",
"Page2" => "page2.php",
"Page3" => "page3.php",
"Page4" => "page4.php"
],
"CATEGORY_NEW" => [
"Page1" => "page1_edit.php",
"Page2" => "page2_edit.php",
"Page3" => "page3_edit.php"
],
"CATEGORY_EMPTY1" => [],
"CATEGORY_EMPTY2" => [],
"SEARCH" => [
"Page1" => "page1_search.php",
"Page2" => "page2_search.php",
"Page3" => "page3_search.php"
],
"BACK" => [
"Home" => "index.php"
]
];
function category_add(array $array, string $category, array $newElement, int $position = 0)
{
if (array_key_exists($category, $array)) {
$categoryArray = $array[$category];
$categoryArray = arrayInsert($categoryArray, $position, $newElement);
$array[$category] = $categoryArray;
} else {
$array[$category] = $newElement;
}
return $array;
}
function arrayInsert($array, $position, $insertArray)
{
$ret = [];
if ($position == count($array)) {
$ret = $array + $insertArray;
} else {
$i = 0;
foreach ($array as $key => $value) {
if ($position == $i++) {
$ret += $insertArray;
}
$ret[$key] = $value;
}
}
return $ret;
}
$newNavigation = category_add($navigation_array, 'CATEGORY_MAIN', ['Page2aaa' => "page2aaa.php"], 1);
echo '<pre>'; print_r($newNavigation);
// create whole new category
$newNavigation2 = category_add($navigation_array, 'CATEGORY_NEW2', ['new' => "new.php"]);
echo '<pre>'; print_r($newNavigation2);
https://www.php.net/manual/en/function.array-splice.php#111204
When trying to splice an associative array into another, array_splice is missing two key ingredients:
a string key for identifying the offset
the ability to preserve keys in the replacement array
This is primarily useful when you want to replace an item in an array with another item, but want to maintain the ordering of the array without rebuilding the array one entry at a time.
<?php
function array_splice_assoc(&$input, $offset, $length, $replacement) {
$replacement = (array) $replacement;
$key_indices = array_flip(array_keys($input));
if (isset($input[$offset]) && is_string($offset)) {
$offset = $key_indices[$offset];
}
if (isset($input[$length]) && is_string($length)) {
$length = $key_indices[$length] - $offset;
}
$input = array_slice($input, 0, $offset, TRUE)
+ $replacement
+ array_slice($input, $offset + $length, NULL, TRUE);
}
$fruit = array(
'orange' => 'orange',
'lemon' => 'yellow',
'lime' => 'green',
'grape' => 'purple',
'cherry' => 'red',
);
// Replace lemon and lime with apple
array_splice_assoc($fruit, 'lemon', 'grape', array('apple' => 'red'));
// Replace cherry with strawberry
array_splice_assoc($fruit, 'cherry', 1, array('strawberry' => 'red'));
?>
Related
The main thing is multidimensional arrays can be random and I don't know exactly how many arrays inside in it. That why function should include recursion and checks does it have more array inside, example below can't do it without pre configuration. Appreciating any help
$arrays = array(
array(
'House' => 'Baratheon',
'Sigil' => 'A crowned stag',
'Motto' => 'Ours is the Fury',
),
array(
'Leader' => 'Eddard Stark',
'House' => 'Stark',
'Motto' => 'Winter is Coming',
'Sigil' => 'A grey direwolf'
),
array(
array('SomeArray' => 'You are cool'),
'House' => 'Lannister',
'Leader' => 'Tywin Lannister',
'Sigil' => 'A golden lion'
),
array(
'Q' => 'Z'
)
);
function next_element($array) {
foreach ($array as $some_type) {
if (is_array($some_type)) {
return true;
} else {
return false;
}
}
}
function check_in($inputs) {
foreach ($inputs as $position => $input) {
if (is_array($input) && next_element($input)) { // case with multidimentional array
check_in($input);
$check_in_result[] = "There are should be recursion!!!!!";
} else { // case with one simple array
$check_in_result[] = $input;
}
}
return $check_in_result;
}
Have tried with array_walk_recursive() but that function is working with all elements and returns as result one array with all keys and values. In this case it should be array(array1, array2, array3, array4) for next stage which is foreach loop.
As resutl it should be:
Array
(
[0] => Array
(
[House] => Baratheon
[Sigil] => A crowned stag
[Motto] => Ours is the Fury
)
[1] => Array
(
[Leader] => Eddard Stark
[House] => Stark
[Motto] => Winter is Coming
[Sigil] => A grey direwolf
)
[2] => Array
(
[SomeArray] => You are cool
)
[3] => Array
(
[House] => Lannister
[Leader] => Tywin Lannister
[Sigil] => A golden lion
)
[4] => Array
(
[Q] => Z
)
)
Try using a recursive function like this:
function parseMyArray($array) {
$result = [];
$row = [];
foreach($array as $key => $item) {
if (is_array($item)) {
$result = array_merge($result, parseMyArray($item));
} else {
$row[$key] = $item;
}
}
return !empty($row) ? array_merge($result, [$row]) : $result;
}
$result = parseMyArray($arrays);
print_r($result);
At each level of a function call, all scalar values with their keys are collected into one array as $row and merged with the $result of a nested function call.
fiddle
I want to create a list where if its already in the array to add to the value +1.
Current Output
[1] => Array
(
[source] => 397
[value] => 1
)
[2] => Array
(
[source] => 397
[value] => 1
)
[3] => Array
(
[source] => 1314
[value] => 1
)
What I want to Achieve
[1] => Array
(
[source] => 397
[value] => 2
)
[2] => Array
(
[source] => 1314
[value] => 1
)
My current dulled down PHP
foreach ($submissions as $timefix) {
//Start countng
$data = array(
'source' => $timefix['parent']['id'],
'value' => '1'
);
$dataJson[] = $data;
}
print_r($dataJson);
Simply use an associated array:
$dataJson = array();
foreach ($submissions as $timefix) {
$id = $timefix['parent']['id'];
if (!isset($dataJson[$id])) {
$dataJson[$id] = array('source' => $id, 'value' => 1);
} else {
$dataJson[$id]['value']++;
}
}
$dataJson = array_values($dataJson); // reset the keys - you don't nessesarily need this
This is not exactly your desired output, as the array keys are not preserved, but if it suits you, you could use the item ID as the array key. This would simplify your code to the point of not needing to loop through the already available results:
foreach ($submissions as $timefix) {
$id = $timefix['parent']['id'];
if (array_key_exists($id, $dataJson)) {
$dataJson[$id]["value"]++;
} else {
$dataJson[$id] = [
"source" => $id,
"value" => 1
];
}
}
print_r($dataJson);
You should simplify this for yourself. Something like:
<?
$res = Array();
foreach ($original as $item) {
if (!isset($res[$item['source']])) $res[$item['source']] = $item['value'];
else $res[$item['source']] += $item['value'];
}
?>
After this, you will have array $res which will be something like:
Array(
[397] => 2,
[1314] => 1
)
Then, if you really need the format specified, you can use something like:
<?
$final = Array();
foreach ($res as $source=>$value) $final[] = Array(
'source' => $source,
'value' => $value
);
?>
This code will do the counting and produce a $new array as described in your example.
$data = array(
array('source' => 397, 'value' => 1),
array('source' => 397, 'value' => 1),
array('source' => 1314, 'value' => 1),
);
$new = array();
foreach ($data as $item)
{
$source = $item['source'];
if (isset($new[$source]))
$new[$source]['value'] += $item['value'];
else
$new[$source] = $item;
}
$new = array_values($new);
PHP has a function called array_count_values for that. May be you can use it
Example:
<?php
$array = array(1, "hello", 1, "world", "hello");
print_r(array_count_values($array));
?>
Output:
Array
(
[1] => 2
[hello] => 2
[world] => 1
)
This question already has answers here:
Count specific values in multidimensional array
(4 answers)
Closed 9 years ago.
I'm looking for a way to count occurence on an array of array.
This is my array :
Array
(
[0] => Array
(
[id] => 671
[title] => BIEND
[img] =>
[ville] => marseille
)
[1] => Array
(
[id] => 670
[title] => BIENC
[img] =>
[ville] => avignon
)
[2] => Array
(
[id] => 669
[title] => BIENB
[img] =>
[ville] => avignon
)
)
And what I would like to have :
Array
(
[avignon] => 2
[marseille] => 1
)
I tried with array_count_values, but it dont seems to be the good way.
Any idea?
You could just go through it manually:
$result = array();
foreach($input as $item)
{
$result[$item['ville']]++;
}
or, slightly nicer perhaps,
$result = array();
foreach($input as $item)
{
$city = $item['ville'];
if(!array_key_exists($city, $result)) {
$result[$city] = 1;
} else {
$result[$city]++;
}
}
Alternatively, you could do some array_map magic to first get an array with all the cities, and then use array_count_values as you planned:
$cities = array_count_values( array_map( function($a) { return $a['ville']; } ) );
Note, I haven't tested this last solution, I personally think the first one expresses the intention better. If you would like to use this one because it is shorter (i.e. less readable) I'll leave it to you to debug and comment it
You can use array_reduce():
$data = Array
(
0 => Array
(
'id' => 671,
'title' => 'BIEND',
'img' => '',
'ville' => 'marseille'
)
,
1 => Array
(
'id' => 670,
'title' => 'BIENC',
'img' => '',
'ville' => 'avignon'
)
,
2 => Array
(
'id' => 669,
'title' => 'BIENB',
'img' => '',
'ville' => 'avignon'
)
);
$result = array_reduce($data, function(&$cur, $x)
{
$cur[$x['ville']] = isset($cur[$x['ville']])?$cur[$x['ville']]+1:1;
return $cur;
}, []);
$my_array = array(...);
$result = array();
foreach ($my_array as $arr) {
$key = $arr['ville'];
if (! array_key_exists($key, $result){
$result[$key] = 1;
continue;
}
$result[$key] += 1;
}
I would write something like this. Array and subArray should be renamed according to their content.
$villes = array();
foreach($yourArray as $subArray) {
if(!in_array($subArray['ville'], $villes)) {
$villes[$subArray['ville']] = 1;
} else {
$villes[$subArray['ville']]++;
}
}
var_dump($villes);
I need your help with my problem. My problem is I have 2 arrays the first one is the main array. The second is the array for my new data.
Let's say I have these arrays.
This is the main array:
Array
(
0 => Array
(
'id' => 1,
'name' => 'Apple',
'age' => 12
)
1 => Array
(
'id' => 2,
'name' => May,
'age' => 13
)
)
This is the second array:
Array
(
1 => Array
(
'gender' => 'Male'
)
2 => Array
(
'gender' => 'Female'
)
)
And I have this loop in PHP
foreach($main_array as &$main){
//this is the loop inside the first array
// how can I add the second array with it?
}
This is the sample output:
[0] => Array
(
[id] => 1
[name] => Apple
[age] => 12
[gender] => Female
)
[1] => Array
(
[id] => 2
[name] => May
[age] => 13
[gender] => Female
)
How can I do that? Any suggestions? That's all thanks.
for($i=0; $i<count($main_array); $i++){
for($j=0; $j<count($second_array); $j++){
if($main_array[$i]['id'] == $j){
$main_array[$i]['gender'] = $second_array[$j]['gender']
}
}
}
I fixed your example code, it wont run otherwise.
<?php
// Test data:
$main_array = Array(
0 => Array(
'id' => 1,
'name' => 'Apple',
'age' => 12
),
1 => Array (
'id' => 2,
'name' => 'May',
'age' => 13
)
);
$lookup = Array(
1 => Array(
'gender' => 'Male'
),
2 => Array(
'gender' => 'Female'
)
);
// Your answer:
foreach ($main_array as &$main) {
if (array_key_exists($main['id'],$lookup)) {
$main['gender'] = $lookup[$main['id']]['gender']; // <-- sets gender value
}
}
// Output it to browser:
echo '<pre>$main_array = '.print_r($main_array,true).'</pre>';
The array_key_exists() check is there to avoid errors such as PHP Notice: Undefined offset: 123 when the $lookup data is incomplete.
If you want to merge all of the data from both arrays:
PHP tools:
The exact behaviors of these functions needs to be studied and tested before usage, to make sure it fits your intent.
// array merge recursive doesn't merge numeric keys
$main_array = array_merge_recursive($main_array, $secondary_array);
// array replace recursive has a downside of replacing stuff
$main_array = array_replace_recursive($main_array, $secondary_array);
Rolling your own:
foreach($main_array as $i => &$main){
if(isset($secondary_array[$i])) {
foreach($secondary_array[$i] AS $key => $value) {
$main[$key] = $value;
}
}
}
Both of the above solutions only apply if the array-indexes of $main_array and $secondary_array match.
In your example your arrays don't match:
- $secondary_array[0] doesn't exist so $main_array[0] will not be populated with a 'gender' value;
- $main_array[2] doesn't exist so $main_array[2] will be created and it will only have a 'gender' value same as $secondary_array[2]['gender']
If you want to only merge some bits and pieces of the arrays:
Rolling your own:
foreach($main_array as $i => &$main) {
if(isset($secondary_array[$i])) and isset($secondary_array[$i]['gender'])) {
$main['gender'] = $secondary_array[$i]['gender'];
}
}
foreach($main_array as &$main){//this is the loop inside the first array
foreach($second_array as &$second){ //this is the loop inside the second array
}
}
foreach($arr1 as $k => $arr1Item) {
$arr1[$k]['gender'] = $arr2[$k]['gender'];
}
I have an array that looks like
Array
(
[1] => Array
(
[0] => Date
[1] => Action
)
[2] => Array
(
[0] => 2011-01-22 11:23:19
[1] => SHARE_TWEET
)
[3] => Array
(
[0] => 2011-01-22 11:23:19
[1] => SHARE_FACEBOOK
)
and many other different values (about 10), what I want to do is I want to count the number of times a string is in the array. I was going to use array_count_values but it doesn't count multidimensional arrays.
Any other options?
This could be done by first flattening the array, and then using array_count_values() on it:
For flattening, here is the trick:
$array = call_user_func_array('array_merge', $arrays);
And then:
$counts = array_count_values($array);
Output:
array (
'Date' => 1,
'Action' => 1,
'2011-01-22 11:23:19' => 2,
'SHARE_TWEET' => 1,
'SHARE_FACEBOOK' => 1,
)
Full code:
$array = call_user_func_array('array_merge', $arrays);
var_export(array_count_values($array));
Any time you're dealing with arrays, especially with loops in PHP I can't string enough suggest you look at the array documentation, You'd be suprised how quickly you realise most of the loops in your code is unnecessary. PHP has a built in function to achieve what you're after called array_walk_recursive. And since you're using PHP5 you can use closures rather that create_function (which can be very troublesome, especially to debug, and can't be optimised by the PHP interpreter afik)
$strings = array();
array_walk_recursive($arr, function($value, $key) use (&$strings) {
$strings[$value] = isset($strings[$value]) ? $strings[$value]+1 : 1;
});
I know, unary statements aren't always clear, but this one is simple enough, but feel free to expand out the if statement.
The result of the above is:
print_r($strings);
Array
(
[Date] => 1,
[Action] => 1,
[2011-01-22 11:23:19] => 2,
[SHARE_TWEET] => 1,
[SHARE_FACEBOOK] => 1,
)
Pseudo Code
$inputArray = // your array as in the example above
foreach ($inputArray as $key => $value) {
$result[$value[1]] = $result[$value[1]] + 1;
}
var_dump($result);
Here is a way to do the job:
$arr = Array (
1 => Array (
0 => 'Date',
1 => 'Action'
),
2 => Array (
0 => '2011-01-22 11:23:19',
1 => 'SHARE_TWEET'
),
3 => Array (
0 => '2011-01-22 11:23:19',
1 => 'SHARE_FACEBOOK'
)
);
$result = array();
function count_array($arr) {
global $result;
foreach($arr as $k => $v) {
if (is_array($v)) {
count_array($v);
} else {
if (isset($result[$v])) {
$result[$v]++;
} else {
$result[$v] = 1;
}
}
}
}
count_array($arr);
print_r($result);
output:
Array
(
[Date] => 1
[Action] => 1
[2011-01-22 11:23:19] => 2
[SHARE_TWEET] => 1
[SHARE_FACEBOOK] => 1
)