I have two sets of array ,first array contains all categories called "all", and second array contains selected categories called "selected", I want to populate this concept to multiple combo box,
$all = [
0 => [
'id'=>1,
'name' => 'news'
],
1 => [
'id'=>2,
'name' => 'tips'
],
2 => [
'id'=>3,
'name' => 'trick'
],
3 => [
'id'=>4,
'name' => 'review'
]
];
$selected = [
0 => [
'id'=>2,
'name' => 'trick'
],
1 => [
'id'=>4,
'name' => 'review'
],
];
I've try to do foreach in foreach , but i have duplicated data when show in combo box, i want to have all data from "all" shown with selected data from "selected".
i just solved my problem in deferent way , first i add default pair of key and value "sel"=>0 in "all" array set, then i loop trough array "all" and array "sel" to get similar value and when it match change sel key to 1 ,this code for further explanation
public static function compare($sel,$all){
// add sel key with default value = 0
foreach($all as $k=>$v){
$all[$k]['sel'] = 0;
}
foreach($all as $k=>$v){
foreach($sel as $k2=>$v2){
// when match change sel to 1
if($v['id'] == $v2['id']){
$all[$k]['sel'] = 1;
}
}
}
return $all;
}
final result :
$all = [
0 => [
'id'=>1,
'name' => 'news',
'sel' => 0
],
1 => [
'id'=>2,
'name' => 'tips',
'sel' => 0
],
2 => [
'id'=>3,
'name' => 'trick',
'sel' => 1
],
3 => [
'id'=>4,
'name' => 'review',
'sel' => 1
]
];
just add if condition when $all['sel'] = 1 they should be selected, thanks all :D
You can get the intersection of both arrays with array_uintersect and a custom callback function (compare).
function compare($a, $b){
if($a['id'] == $b['id']){
return 0;
}
return 1;
}
$res = array_uintersect($selected, $all,"compare");
print_r($res);
>Array ( [0] => Array ( [id] => 2 [name] => trick ) [1] => Array ( [id] => 4 [name] => review ) )
After that you only need to loop through the final array and set the corresponding check boxes.
If you want to compare by name just create another callback function.
function compare2($a, $b){
if($a['name'] == $b['name']){
return 0;
}
return 1;
}
The duplicates are caused by the inner for loop continuing to create select elements even after it has found a selected element. You can avoid having an inner loop and using php's in_array() function to check if $all is in $selected like this:
$x = '';
foreach($all as $a){
if(in_array($a, $selected)){
$x .= '<option selected>'.$a['id'].'Selected </option>';
}else{
$x .= '<option>'.$a['id'].'Not selected </option>';
}
}
echo $x;
Note that in_array will check all values of the elements, so for example element with id 2 but different name will appear as not selected. You may want to change both names to tips. I hope that helps.
Related
I've got a 4-level nested array, each level represent a hiereachy in an organization. Each level's key is the hierarchy value, and inside it there is the id of it in the array. The last level is only the value-id pair:
$data = [
"top_level_data1" => [
'top_level_id' => 0,
'sub_level_1' => [
'sub_level_1_id' => 0,
'sub_level_2_data1' => [
'sub_level_2_id' => 0,
'sub_level_2_data' => [
0 => "some_val"
1 => "some_other_val"
]
]
]
],
"top_level_data2" => [
'level_1_id' => 1,
'sub_level_1_other' => [
'sub_level_1_id' => 1,
'sub_level_2_data2' => [
'sub_level_2_id' => 1,
'sub_level_3_data1' => [
2 => "another_val"
3 => "bar"
4 => "foo"
]
],
'sub_level_2_data3' => [
'sub_level_2_id' => 2,
'sub_level_3_data2' => [
5 => "foobar"
6 => "hello"
7 => "goodbye"
]
]
]
]
];
I want to extract it to separate arrays that would contain the hierarchy value-id pairs.
Expected output from the above example (without the ids of the above level):
$top_level = [
0 => "top_level_data1",
1 => "top_level_data2"
]
$sub_level_1 = [
0 => "sub_level_1",
1 => "sub_level_1_other"
]
$sub_level_2 = [
0 => "sub_level_2_data1",
1 => "sub_level_2_data2",
2 => "sub_level_2_data3"
]
$sub_level_3 = [
0 => "some_val"
1 => "some_other_val"
2 => "another_val"
3 => "bar"
4 => "foo"
5 => "foobar"
6 => "hello"
7 => "goodbye"
]
I've tried using the RecursiveIterator but that does not work (At first I wanted to use it just to check if it iterates correctly, even before assignting the key-values as I wanted, but it just doesn't do it as I wanted):
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($data));
foreach($it as $key => $val) {
$level[$it->getDepth()][] = $val;
}
This can do it:
$result = [];
$recursive = null;
$recursive = function($args,$level=0) use (&$recursive,&$result){
foreach($args as $k=>$v){
if(is_array($v)){
$result[$level][]=$k;
$recursive($v,$level+1);
} else if(is_string($v)){
$result[$level][]=$v;
}
}
};
$recursive($data);
var_export($result);
But your expected output isn't ok. Because i think sub_level_2_data must be sub_level_3_data (in the $data array above). And the hole sub_level_3*level is missing in your expected output.
With this code you get an result array instead of separate filled variables.
Will not explain it in detail, but try to understand whats happening here and you can learn some new php stuff.
I have an array with a structure like:
$arr = [
'data1' => [ /* some data */],
'data2' => [
'sub-data1' => [
[
'id' => 1
'status' => 'active'
],
[
'id' => 2
'status' => 'not-active'
]
],
'sub-data2' => [
[
'id' => 3
'status' => 'active'
],
[
'id' => 4
'status' => 'active'
]
]
]
]
Is there a simple way in which I can count how many sub-dataxxx have any item with a status is active?
I have managed to do this with nested foreach loops, but I'm wondering if there is a more simple method?
The above example should show the number of active entries as 2, as there are 2 sub-data elements with active statuses. This ignores any non-active statuses.
Edit: To clarify my expected result
I am not wanting to count the number of status = active occurrences. I'm wanting to count the number of sub-dataxxx elements that contain an element with status = active.
So in this instance, both of sub-data1 and sub-data2 contain sub-elements that contain status = active, therefore my count should be 2.
you can do it quite easily with a function like this
function countActiveSubData(array $data): int
{
return array_reduce($data, function ($res, $sub) {
foreach ($sub as $d) {
if ('active' === $d['status']) {
return $res + 1;
}
}
return $res;
}, 0);
}
you can call it on a single data or if you want to get the result for entire $arr you can call it like this
$result = array_map('countActiveSubData', $arr);
// the result will be [
'data1' => 0,
'data2'=> 2
....
]
I need to make a function to pass any value of this array and return its key without using foreach. as example if US is passed,5 will return.
$array = [
5 => [
0 => 'US',
1 => 'AI'
],
20 => [
0 => 'GB',
1 => 'GG',
2 => 'IM',
3 => 'JE'
],
23 => [
0 => 'DK'
]
];
// Filter your array to get subarrays where 'US' exists
$filterd = array_filter($array, function($v) { return in_array('US', $v); });
// Take the first key from filtered result:
print_r(array_keys($filterd)[0]);
Demo is here.
I have the following array to show menu's based on the order the user specified.
The array is as follows:
$menuArray = [
'Main Street' => [
['/index.php', 'Home'],
['/city.php', $cityData[$user->city][0]],
['/travel.php', 'Travel'],
['/bank.php', 'Bank'],
['/inventory.php', 'Inventory'],
['/dailies.php', 'Dailies'],
],
'Activities' => [
(!$my->hospital) ? ['/hospital.php', 'Hospital'] : [],
(!$my->hospital && !$my->prison) ? ['/crime.php', 'Crime'] : [],
['/missions.php', 'Missions'],
['/achievements.php', 'Achievements'],
],
'Services' => [
['/hospital.php', 'Hospital'],
['/prison.php', 'Prison'],
['/search.php', 'Search'],
],
'Account' => [
['/edit_account.php', 'Edit Account'],
['/notepad.php', 'Notepad'],
['/logout.php', 'Logout'],
]
];
I have a column menu_order stored in the database, which has a default value of 0,1,2,3,4, but this can change per user as they will be able to change their menu to their likes.
What I'd like to achieve:
0 => Main Street
1 => Activities
2 => Services
3 => Account
4 => Communication
To get the menu order, I do
$menuOrder = explode(',', $user->menu_order);
But I'm not sure how to handle the foreach for displaying the menu.
Here's one way to do it -- use replacement rather than a sorting algorithm.
Code: (Demo)
$menuArray = [
'Main Street' => [],
'Activities' => [],
'Services' => [],
'Account' => []
];
$lookup = [
0 => 'Main Street',
1 => 'Activities',
2 => 'Services',
3 => 'Account',
4 => 'Communication'
];
$customsort = '4,2,1,3,0';
$keys = array_flip(explode(',', $customsort)); convert string to keyed array
//var_export($keys);
$ordered_keys = array_flip(array_replace($keys, $lookup)); // apply $lookup values to keys, then invert key-value relationship
//var_export($ordered_keys);
$filtered_keys = array_intersect_key($ordered_keys, $menuArray); // remove items not on the current menu ('Communication" in this case)
//var_export($filtered_keys);
$final = array_replace($filtered_keys, $menuArray); // apply menu data to ordered&filtered keys
var_export($final);
Output:
array (
'Services' =>
array (
),
'Activities' =>
array (
),
'Account' =>
array (
),
'Main Street' =>
array (
),
)
And here's another way using uksort() and a spaceship operator:
$ordered_keys = array_flip(array_values(array_replace(array_flip(explode(',', $customsort)), $lookup)));
uksort($menuArray, function($a, $b) use ($ordered_keys) {
return $ordered_keys[$a] <=> $ordered_keys[$b];
});
var_export($menuArray);
As a consequence of how your are storing your custom sort order, most of the code involved is merely to set up the "map"/"lookup" data.
You could try something like this to produce the menu:
function display_menu($menus, $m) {
if (!isset($menus[$m])) return;
echo "<ul>";
foreach ($menus[$m] as $item) {
if (!count($item)) continue;
echo "<li>{$item[1]}\n";
}
echo "</ul>";
}
$menuMap = array(0 => 'Main Street',
1 => 'Activities',
2 => 'Services',
3 => 'Account',
4 => 'Communication');
$menuOrder = explode(',', $user->menu_order);
foreach ($menuOrder as $menuIndex) {
$thisMenu = $menuMap[$menuIndex];
display_menu($menuArray, $thisMenu);
}
Small demo on 3v4l.org
I have an array based MySql database.
This is the array.
[
0 => [
'id' => '1997'
'lokasi_terakhir' => 'YA4121'
]
1 => [
'id' => '1998'
'lokasi_terakhir' => 'PL2115'
]
2 => [
'id' => '1999'
'lokasi_terakhir' => 'PL4111'
]
]
How can I get the element lokasi_terakhir that grouped by the first character ? What the best way ?
This is the goal :
[
"Y" => 1,
"P" => 2
]
Please advise
Here are two refined methods. Which one you choose will come down to your personal preference (you won't find better methods).
In the first, I am iterating the array, declaring the first character of the lokasi_terakhir value as the key in the $result declaration. If the key doesn't yet exist in the output array then it must be declared / set to 1. After it has been instantiated, it can then be incremented -- I am using "pre-incrementation".
The second method first maps a new array using the first character of the lokasi_terakhir value from each subarray, then counts each occurrence of each letter.
(Demonstrations Link)
Method #1: (foreach)
foreach($array as $item){
if(!isset($result[$item['lokasi_terakhir'][0]])){
$result[$item['lokasi_terakhir'][0]]=1; // instantiate
}else{
++$result[$item['lokasi_terakhir'][0]]; // increment
}
}
var_export($result);
Method #2: (functional)
var_export(array_count_values(array_map(function($a){return $a['lokasi_terakhir'][0];},$array)));
// generate array of single-character elements, then count occurrences
Output: (from either)
array (
'Y' => 1,
'P' => 2,
)
You can group those items like this:
$array = [
0 => [
'id' => '1997',
'lokasi_terakhir' => 'YA4121'
],
1 => [
'id' => '1998',
'lokasi_terakhir' => 'PL2115'
],
2 => [
'id' => '1999',
'lokasi_terakhir' => 'PL4111'
]
];
$result = array();
foreach($array as $item) {
$char = substr($item['lokasi_terakhir'], 0, 1);
if(!isset($result[$char])) {
$result[$char] = array();
}
$result[$char][] = $item;
}
<?php
$array=[
0 => [
'id' => '1997',
'lokasi_terakhir' => 'YA4121'
],
1 => [
'id' => '1998',
'lokasi_terakhir' => 'PL2115'
],
2 => [
'id' => '1999',
'lokasi_terakhir' => 'PL4111'
]
];
foreach($array as $row){
$newArray[]=$row['lokasi_terakhir'][0];
}
print_r(array_flip(array_unique($newArray)));
this code gets the first letter of the fields lokasi_terakhir , get the unique values to avoid duplicates and just flips the array to get the outcome you want.
The output is this :
Array ( [Y] => 0 [P] => 1 )