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

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']);
}

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)

String to Multidimensional Array with merging and sorting

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[] = ....

Comparing arrays until I have a unique array

I have the following multidimensional array called $existing_combinations
Array
(
[0] => Array
(
[1] => 6
[2] => 7
[3] => 9
)
[1] => Array
(
[1] => 1
[2] => 21
[3] => 9
)
[2] => Array
(
[1] => 1
[2] => 7
[3] => 9
)
)
I then generate a new array ($new_combination) which has a combination of the same set of values. Example:
Array
(
[1] => 6
[2] => 21
[3] => 9
)
I then test if $new_combination exists in $existing_combinations with the following in the hope that I will end with a unique combination in $new_combination:
foreach($existing_combinations as $key => $combination){
while($new_combination == $combination){
$new_combination = generateNewCombination();
}
}
The problem is that if $new_combination matches an array that is not at index 0, then when I generate a new combination I am at risk of this matching a $combination that has already been tested against (and will not be tested again).
Sorry if this is a simple one but I'm struggling to think of how I can ensure $new_combination will always end up unique.
Any ideas?
Thanks
You can use in_array in this case, because php compares arrays as value. So, the code can be:
while(in_array($new_combination = generateNewCombination(), $existing_combinations));
print_r($new_combination);
I wrote the below before realizing that in_array can also see if an array exists within an array. So you can simply do this:
if (!in_array($new_combination, $existing_combinations)) {
// It's unique.
}
In the below outdated bit, see the note on using sort, if a different sequence of the same numbers isn't considered unique for your purposes.
[ For Entertainment ]
May not be the most elegant way around, but I would simply do this to keep it simple:
$combo_hashes = [];
// Implode the existing combos into strings.
foreach($existing as $vals) {
$combo_hashes[] = implode(':', $vals);
}
Then, all you need to check with your new combo is:
// Check if the "hash"-string already exists.
if (!in_array( implode(':', $new_combo), $combo_hashes)) {
// ... and we're unique.
}
This presumes that you consider [1,3,2] different from [2,1,3]. If they are equivalent (I don't know what your use case is), you should sort($vals); before you generate the check-strings.
Merge all the second level arrays and run array_unique() to get rid of the duplicate values.

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);

PHP Array insert into MySQL table as individual rows

I am trying to insert multiple rows in a MySQL table from PHP arrays. I managed with with help of other members to get set of values in a pair of brackets but when i try to insert this i get "Error: Column count doesn't match value count at row 1" I donot know where am i going wrong. my codes are as below: (The number of values i get vary according to user input)
$docno1=array();
$serialno = array();
$acc_name = array();
$debit = array();
$credit = array();
for ($i=1;$i<=$rowcount;$i++)
{
//echo 'Accountname'.$i.' :'.($_GET['accname'.$i]).'<br>';
$docno1 [] = ($_GET['docno']);
array_unshift($docno1,"");
unset($docno1[0]);
$serialno [] = $i;
array_unshift($serialno,"");
unset($serialno[0]);
$acc_name[] = ($_GET['accname'.$i]);
array_unshift($acc_name,"");
unset($acc_name[0]);
$debit[] = ($_GET['DrAmount'.$i]);
array_unshift($debit,"");
unset($debit[0]);
$credit[] = ($_GET['CrAmount'.$i]);
array_unshift($credit,"");
unset($credit[0]);
}
$sum_dr = array_sum ($debit);
$sum_cr = array_sum ($credit);
echo ' values of $multi<br>';
$multi = array(
($docno1),
($serialno), //Array for a row of fields
($acc_name),
($debit),
($credit),
($docno1)
);
print_r($multi);
$new = array();
foreach($multi as $key=>$value) {
$new[] = "'".implode("','", $value)."'";
}
echo '<br>Values of $new <br>';
print_r($new);
$query = "(".implode("), (",$new).")";
echo $query.'<br>';
mysql_query("INSERT INTO docitems (`docno`,`itemno`,`accountname`,`debit`,`credit`, `picrefno`) VALUES ".$query.";") or die('Error: ' . mysql_error());
echo "Inserted successfully";
die;
The results i get are :
values of $multi
Array
(
[0] => Array
(
[1] => 3434
[2] => 3434
)
[1] => Array
(
[1] => 1
[2] => 2
)
[2] => Array
(
[1] => Lemon
[2] => Kidney Beans
)
[3] => Array
(
[1] => 20
[2] => 10
)
[4] => Array
(
[1] => 0
[2] => 0
)
[5] => Array
(
[1] => 3434
[2] => 3434
)
)
Values of $new
Array
(
[0] => '3434','3434'
[1] => '1','2'
[2] => 'Lemon','Kidney Beans'
[3] => '20','10'
[4] => '0','0'
[5] => '3434','3434'
)
('3434','3434'), ('1','2'), ('Lemon','Kidney Beans'), ('20','10'), ('0','0'), ('3434','3434')
Error: Column count doesn't match value count at row 1
mysql_query("INSERT INTO docitems (`docno`,`itemno`,`accountname`,`debit`,`credit`, `picrefno`) VALUES ".$query.";") or die('Error: ' . mysql_error());
You are trying to insert something into 6 fields, so that $query string must have 6 values in it, or you get this error.
You have a lot of $query's that are 2 values. And that's not 6
It looks to me as if you are mapping your array the wrong way round. You're trying to add two records with six fields each, but what you're actually putting into the SQL statement are six records with two fields each.
This is why MySQL is complaining -- because you've told it you want to update six fields, but in each of the records you've given it, you've only specified two fields.
You need to build your array differently.
I assume that $docno1, $serialno, $acc_name, $debit and $credit will always all have the same number of array elements (it appears from your code that you are assuming this, so I'll follow you in your assumption).
In that case, you need to build your array something like this:
$multi = array();
foreach($docno1 as $key=>value) {
$multi[] = array(
$docno1[$key],
$serialno[$key], //Array for a row of fields
$acc_name[$key],
$debit[$key],
$credit[$key],
$docno1[$key])
}
Replace the block in your code where you set $multi with this, and your program should work.
Look at what print_r($multi) looks like now, and you'll see the difference.
(note, there are more efficient ways of writing your whole program than this, but I've focused on giving you a drop-in replacement for this specific bit, to help show you where you were going wrong, rather than simply rewriting the whole program for you)
Hope this helps.
If the error is occurring when trying to insert a row to your table, try specifying the list of fields, in the insert query -- this way, the number of data in the values clause will match the number of expected columns.
Else, MySQL expects six columns : it expects the specific inserts -- for which you didn't specify a value.

Categories