String to Multidimensional Array with merging and sorting - php

I have this sort of string that come from my database after many use of CONCAT().
1, AA, 6, 10; 1, Z, 1, 5; 2, AE, 1, 5; 2, AF, 6, 10; 3, X, 1, 5; 3, Y, 5, 10
In order to have something clear, let's say this :
The large string is made of multiple substring, all ending by a ;
Each substring is made of four elements :
A first number. Let's call it the Group
A letter or group of letters. They are called the Section
A second number. We will call it From
A third and last number. We will call it To
Using this code
$data = "1, AA, 6, 10; 1, Z, 1, 5; 2, AE, 1, 5; 2, AF, 6, 10; 3, X, 1, 5; 3, Y, 5, 10";
echo $data;
$ret = array_map (
function ($_) {return explode (', ', $_);},
explode (';', $data)
);
I get the following multidimensional array
Array
(
[0] => Array
(
[0] => 1
[1] => AA
[2] => 6
[3] => 10
)
[1] => Array
(
[0] => 1
[1] => Z
[2] => 1
[3] => 5
)
[2] => Array
(
[0] => 2
[1] => AE
[2] => 1
[3] => 5
)
[3] => Array
(
[0] => 2
[1] => AF
[2] => 6
[3] => 10
)
[4] => Array
(
[0] => 3
[1] => X
[2] => 1
[3] => 5
)
[5] => Array
(
[0] => 3
[1] => Y
[2] => 5
[3] => 10
)
)
I want to end with a multidimensional array that looks like that :
Array
(
[0] => Array
(
[0] => 1
[1] => Array
(
[0] => Z
[1] => 1
[2] => 5
)
[2] => Array
(
[0] => AA
[1] => 6
[2] => 10
)
)
[1] => Array
(
[0] => 2
[1] => Array
(
[1] => AE
[2] => 1
[3] => 5
)
[2] => Array
(
[1] => AF
[2] => 6
[3] => 10
)
)
[2] => Array
(
[0] => 3
[1] => Array
(
[1] => X
[2] => 1
[3] => 5
)
[2] => Array
(
[1] => Y
[2] => 6
[3] => 10
)
)
)
I don't know what's the best method to do it in order to get this result nor if it's possible without too complex operations.
What's the best approach to get the final result ? Should I work on the "raw" multidimensional array or should I work from the string from the beginning ?
Merging arrays with same Group
First, I want to merge substring starting with the same Group value. The rest of each string then become another array inside the newly created array.
I think I can do this by parsing the initial array (Or maybe the string itself ?) and pushing the results in a new one, merging the data in the same time.
In my example, it has been done to the six starting arrays that are now grouped into three arrays.
Sorting using the From and To values
After my substrings with the same Group value are combined into arrays, I want to sort these arrays so the To value of a sub-array is always smaller to the From value of the next one.
The initial string are always generated with the following rules :
There will never be overlapping From and To values like that : 1,5 - 4,7. It would be either 1,4 - 5,7 or 1,5 - 6,7
There will never be missing number in a sequence so you will never have something like 1,3 - 5,7
The From and To value of the same array can be the same. So you can get : 1,4 - 5,5 - 6,7
That's why 1, AA, 6, 10; 1, Z, 1, 5; has been sorted to Z, 1, 5 followed AA, 6, 10. Is there a PHP function that can do this kind of sorting (By comparing values with a different key) or should I create my own ?
Also, if you think that I should totally change the way I want to do this (Using multidimensional arrays...) and you have some ideas, go ahead and share them. I'm also here to learn new way to do things.
Edition concerning Database structure
As stated by #deceze, it may be easier to construct my initial string differently during my SQL query. I have tried it but I'm probably not skilled enough to get what I want. My database looks like that :
Database Structure
As you can see, all the rows are linked by a MasterID. This is because I'm doing a 1 to n query on multiple table.
So far, my query looks like that (I removed all the unnecessary stuff from it) :
SELECT s.MasterID,
GROUP_CONCAT(CONCAT( CONCAT( CONCAT( CONCAT( CONCAT(
s2d.Group, ', '),
s2d.Section, ', '),
s2d.From),', '),
s2d.To) SEPARATOR '; ') AS Concatstuff,
FROM table1 AS s
JOIN table2 AS s2d
ON s2d.MasterID = s.MasterID
WHERE MasterID = $MasterID (A PHP variable)
Because of the 1 to N relation, I don't know how to make this differently. Maybe I could keep it simpler and perform two queries instead of one. In the first query, I get the information from table1 and in the second query, the informations from table2.
But if you know a way to do all of that in only one query, I'm eager to learn how you can do this !

I'd recommend modifying your MySQL query before making many PHP changes.
That massive list of concats will grow quite large, eventually you may even need to adjust the MySQL config setting for GROUP_CONCAT() since it'll truncate after a certain length.
Instead, we can keep the GROUP_CONCAT() and group specifically on individual masterid / group combinations with a GROUP BY. Additionally, GROUP_CONCAT() has an ORDER BY attribute which should solve the sorting issue:
SELECT
s.MasterID,
s2d.`group`,
GROUP_CONCAT(
s2d.`section`, ',', s2d.`from`, ',', s2d.`to`
ORDER BY `from`, `to`
SEPARATOR ';'
) AS Concatstuff
FROM
table1 AS s
JOIN table2 AS s2d
ON s2d.MasterID = s.MasterID
GROUP BY
s.MasterID, s2d.`group`
WHERE
s.MasterID = $MasterID;
This should give us data similar to:
MasterID group Concatstuff
2 1 z,1,5;aa,6,10
2 2 ae,1,5;af,6,10
2 3 x,1,5;y,6,10
Assuming you've retrieved this from the database and have it stored in an array named $results, we can iterate over it like:
$final_groups = array();
foreach ($results as $group) {
// your original `array_map()` logic:
$split_group = array_map(function($_) {
return explode(',', $_);
},
explode(';', $group['Concatstuff'])
);
// ... any other processing you want to do
// store the results:
$final_groups[$group['group']] = $split_group;
}
Note: to explicitly answer your question
Is there a PHP function that can do this kind of sorting
Yes, usort():
function sort_group($a, $b) {
// [1] = 'from'
// [2] = 'to'
if ($a[1] == $b[1]) {
if ($a[2] == $b[2]) {
return 0;
}
return ($a[2] < $b[2]) ? -1 : 1;
}
return ($a[1] < $b[1]) ? -1 : 1;
}
usort($split_group, 'sort_group');
You can customize the comparison logic within sort_group() to match whatever you want it to be. Above, I have it sorting on both from and to =]

Trying to give a general answer without writing your code for you:
For each group, you would set use the group number as index for the contained data.
For each group, you will write its group index into the element with index string prefix plus the number zero: $ret1[$group_number]['d0'] = $group_number;. It will get overwritten every time you add stuff to the group.
Then add the group content with some string index appropriate for sorting. I would propose producing an index using sprintf(), like $idx = sprintf('d%05.1f%05.1f', $from, $to);, so the group number will always be sorted ahead. Again here the prefix. Add it with $ret1[$group_number][$idx] = $group_array;.
Once you have completed this for all input data, run over it for sorting and finishing:
Iterate over all groups in $ret1, sort them by keys and remove the keys with array_values(). Add them to a new array with $ret[] = ....

Related

print the array when it is exploded

In the below code i am getting the output
Array ( [0] => 1 [1] => 2 )
but the expected output is
Array ( [0] => 1 [1] => 2 [2] => 3) Array ( [0] => 1 [1] => 2 )
why is it always executing the second if condition? although the first condition is also true.
this is the code I have tried
<?php
$test_arr=array();
$temp_option_arr=array();
$option_arr=array();
$options_array_val = Array ( 0 => "animals:1", 1 => "animals:2", 2 => "animals:3", 3 => "birds:1", 4 => "birds:2" );
foreach($options_array_val as $options_val)
{
$search_filter = explode(":", $options_val);
print_r($search_filter);
if(!in_array($search_filter[0],$option_arr))
{
array_push($temp_option_arr,$search_filter[1]);
array_push($option_arr,$search_filter[0]);
$temp_option_arr=array();
}
array_push($temp_option_arr,$search_filter[1]);
}
$test_arr[$search_filter[0]]=$temp_option_arr;
$find_species = array();
if(!empty($test_arr['animals']))
{
$find_species = $test_arr['animals'];
print_r($find_species);
}
if(!empty($test_arr['birds']))
{
$find_species = $test_arr['birds'];
print_r($find_species);
}
?>
The line
$test_arr[$search_filter[0]]=$temp_option_arr;
is out of the foreach scope, therefore it only sets the array for the birds and not for the animals, so you need to move it one line upper.
Also, you assign temp_option_arr to a value
array_push($temp_option_arr,$search_filter[1]);
then set it back to empty array without using it
$temp_option_arr=array();
You can remove the first one I guess
You clear $temp_option_arr in the first part of your code, so it will have nothing that concerns animals by the time you exit the first loop.
But instead of using all these different arrays, just build an associative array keyed by the species (animals, birds, ...), and with as values the arrays of IDs (1, 2, 3, ... i.e., the parts after the :):
foreach($options_array_val as $options_val) {
list($species, $id) = explode(":", $options_val);
$option_arr[$species][] = $id;
}
After this loop the structure of $option_arr is this:
Array (
"animals" => Array (1, 2, 3)
"birds" => Array (1, 2)
)
I think you can do what you want with that. For instance to only get the animals:
$option_arr["animals"]
which is:
Array (1, 2, 3)

PHP how to loop through an array and grab specific parts

Ok so im trying to grab a single part of an array, the array is the return for some stats there can be up to 8 players in the server, the data i get is like this
Array (
[0] => 1
[1] => Player1
[2] =>
[3] => 1
[4] => 0
[5] => 0
[6] => 0
[7] => 0
[8] => 1
[9] => Player2
[10] =>
[11] => 1
[12] => 0
[13] => 0
[14] => 0
[15] => 0
)
so that is the return for 2 players, as i said it can be up to 8, anyway i am trying to just grab the player names and im not sure how to go about it ( Player1 , Player2 ) is the only data i need, any help is appreciated, it always returns 8 pieces of data per player never more never less if that makes it easier
(sorry for bad english)
If you have control over the return type, I would restructure the array being returned either into an Object or an array of arrays where each sub array contains all of the information for one player.
I you don't have control over the return type and the Player's name is always in the second position within the return array you can use a while loop to iterate over the array. Use a counter starting at 1 and then increment the counter by 8 each time through the loop. For example:
$i= 1;
while ($i < count($return_var)) {
$name = $return_var[$i];
// do something w/ name
$i += 8;
}
You want to get all items that are not '' (assuming empty string), 0 or 1 (assuming integers here):
$playerNames = array_diff($array, array('', 0, 1));
If you more specifically know what the format of the array actually is, you can also create some little "parser":
$playerSize = 8;
$playerFields = array('_1', 'name', '_3', '_4', '_5', '_6', '_7', '_8');
$players = array_chunk($array, $playerSize);
foreach($players as &$player)
{
$player = (object) array_combine($playerFields, $player);
}
unset($player);
This does parse $array into another array $players that contains one object per each player. Each object has the name property now:
printf("%d Player(s):\n", count($players));
foreach($players as $i => $player)
{
printf("#%d: %s\n", $player->name);
}
if the array you pasted is called $array and the values of the places without players are always numeric (like your example), this code will work:
$players = array();
foreach($array as $player){
if(!empty($player) && !is_numeric($player){
$players[]=$player;
}
}
var_dump($players);

How do I insert a value in between two keys in an array using php?

I have an array with 3 values:
$b = array('A','B','C');
This is what the original array looks like:
Array ( [0] => A [1] => B [2] => C )
I would like to insert a specific value(For example, the letter 'X') at the position between the first and second key, and then shift all the values following it down one. So in effect it would become the 2nd value, the 2nd would become the 3rd, and the 3rd would become the 4th.
This is what the array should look like afterward:
Array ( [0] => A [1] => X [2] => B [3] => C )
How do I insert a value in between two keys in an array using php?
array_splice() is your friend:
$arr = array('A','B','C');
array_splice($arr, 1, 0, array('X'));
// $arr is now array('A','X','B','C')
This function manipulates arrays and is usually used to truncate an array. However, if you "tell it" to delete zero items ($length == 0), you can insert one or more items at the specified index.
Note that the value(s) to be inserted have to be passed in an array.
There is a way without the use of array_splice. It is simpler, however, more dirty.
Here is your code:
$arr = array('A', 'B', 'C');
$arr['1.5'] = 'X'; // '1.5' should be a string
ksort($arr);
The output:
Array
(
[0] => A
[1] => B
[1.5] => X
[2] => C
)

If value exists in one PHP array, add value to second array

I have two PHP arrays. One contains a group name and another contains a pay wage value.
$group_wages_array = Array ( [0] => 1 [1] => 4 [2] => 1 [3] => 3 );
This means there are four employees on the schedule. Two are assigned to group 1, another to group 4 and the last to group 3.
The second array is as follows:
$tot_wages_array = Array ( [0] => 500 [1] => 44 [2] => 80 [3] => 11.25 );
This is a sample array of each employee's wage. Both arrays are constructed in order as values are added in a mysql while loop as it pulls the info from the database.
Later on down the line, I combine the two arrays to get one array where the key is the group number and the value is the total wages for that group:
$combined_group_wages = array_combine($group_wages_array, $tot_wages_array);
This works like a charm EXCEPT for when more than one employee is assigned to the same group. These arrays are built in a mysql while loop as it loops through each employee's info:
array_push($tot_wages_array, $totemp_wages_sch); // Add their wage to the array
array_push($group_wages_array, $emp_data['group_id']); // Add their group to the array
Instead of just pushing the data to the array, I need to do this... I know the english but I don't know how to code it:
If $emp_data['group_id'] exists as value in $group_wages_array, add nothing to this array but get the key. Add $totemp_wages_sch to $tot_wages_array where key = group_wages_array key
I know it sounds more like an SQL query but I have to keep the keys and values in order so that they can be combined later in the page. If I can get this to work right, The arrays shown in the example would be:
$group_wages_array = Array ( [0] => 1 [1] => 4 [2] => 3 );
$tot_wages_array = Array ( [0] => 580 [1] => 44 [2] => 11.25 );
$combined_group_wages = array_combine($group_wages_array, $tot_wages_array);
$combined_group_wages = Array ( [1] => 580 [4] => 44 [3] => 11.25 );
...I've got to make this work using PHP. Any ideas?
I came up with a solution based on a combination of two of the answers submitted below. Here it is if it can help someone:
if(in_array($emp_data['group_id'], $group_wages_array)){
$key = key($group_wages_array);
$tot_wages_array[$key] += $totemp_wages_sch;
} else {
array_push($group_wages_array, $emp_data['group_id']);
array_push($tot_wages_array, $totemp_wages_sch);
}
This should do it:
$group_wages_array = array(1, 4, 1, 3);
$tot_wages_array = array(500, 44, 80, 11.25);
$combined_group_wages = array();
for ($i=0; $i<count($group_wages_array); $i++) {
$group = $group_wages_array[$i];
if (array_key_exists($group_wages_array[$group], $combined_group_wages)) {
$combined_group_wages[$group] += $tot_wages_array[$i];
} else {
$combined_group_wages[$group] = $tot_wages_array[$i];
}
}
print_r($combined_group_wages);
Yields:
Array
(
[1] => 580
[4] => 44
[3] => 11.25
)
But I recommend that you just switch to using objects to better represent your data.
If I could see the entirety of the code that would help a lot, but here's your English converted to php. Show me more code and I can perfect it, until then try this ->
if(in_array($emp_data['group_id'], $group_wages_array)){
$key = key($group_wages_array);
$tot_wages_array[$key] = $totemp_wages_sch;
} else {
array_push($group_wages_array, $emp_data['group_id']);
}

Getting all possible combinations of N items in X Groups

I have a list of Groups that can vary in number, with Items in these groups that also vary in number. I've been racking my head over a way to get all possible combinations of 1 Item from every Group.
Bonus: I also need all combinations of not having every items from a group.
I've seen and done what was mentioned before, but that requires knowing the number of groups to begin with.
To be more specific about what I'm doing, I would like to generate products with exact pricing based off product options. Here's an example list:
So it would generate products like:
UV Coating, Qty 500, Color 4:0
UV Coating, Qty 500, Color 4:1
etc...
Each of these Groups has an ID, and each item has a Group_Item_ID. So I can put them in an array such as:
$selections[1][...] // 1 = Coating
$selections[2][...] // 2 = Quantity
// ... = all selected Items in group
Hope I explained it well enough. I'm just not able to wrap my head around how to do this when the number of Groups are variable also.
Here's an example array for the groups and their items:
Array
(
[0] => Array
(
[0] => 2
[1] => 3
)
[1] => Array
(
[0] => 10
[1] => 11
[2] => 12
)
[2] => Array
(
[0] => 16
[1] => 17
)
[3] => Array
(
[0] => 19
[1] => 20
)
)
Try this:
function c($groups, $prefix='')
{
$result = array();
$group = array_shift($groups);
foreach($group as $selected) {
if($groups) {
$result = array_merge($result, c($groups, $prefix . $selected. ' '));
} else {
$result[] = $prefix . $selected;
}
}
return $result;
}

Categories