create unique ids from multidimensional array - php

I have an array with small example below
Array (2)
system => Array (1)
system_id => 3
proc => Array (4)
proc_id => 5
proc_or => 1
proc_owner => 7751
results => Array (7)
0 => Array (5)
process_id => 101
process => 1335
process_name => xa
process_owner => xo
rating => 67.554
1 => Array (6)
process_id => 122
process => 1335
process_name => xa
process_owner => xo
rating => 33.554
proc_rel => xf
2 => Array (5)
process_id => 101
process => 1227
process_name => xd
process_owner => xa
rating => 123.78
3 => Array (8)
process_id => 101
process => 1291
process_name => xa
process_owner => xo
rating => 64.241
proc_rel => xf
proc_rel_id => 1474
proc_rel_owner => xm
I need to be able to organise this so that it contains only unique process_id values, so results 2 and 3 would be removed and the rating for that remaining unique id is the sum of all ratings for the records with that id so the results 0 rating id would become the sum of results 0 2 and 3.
There are thousands of records so its not practyical to do it without some sort of automated loop
I was thinking of maybe creating a new array and as its being processed
If the process_id is not in new array add it and all related data
If the process id is already in the array just add(+) the value of rating to the existing value.
I have tried to adapt a couple of loops that ive found but they dont seem to work properly.
Not sure if this is the way to go and Im not sure how to do it anyway so any suggestions greatly appreciated.

If the data set is big, then better try to adjust your database query or change file structure when its generated. If it isnt possible then the only rational way is to create new array:
$newArray = ();
foreach($array['proc']['results'] as $result) {
if (isset($newArray[$result['process_id']]) {
$newArray[$result['process_id']]['rating'] += $result['rating'];
} else {
$newArray[$result['process_id']] = $result;
}
}

Related

usort of session array not outputting as expected

I have a grid of img squares that can be dragged into any order using the sortable library. Each img is a visual representation of a result from a mySQL db query that selects any image that shares an 'imageparent' identifier. The order they're presented in the grid is taken from the 'imageorder' column in the database and starts at 0 and works in sequence up to the nth number of images returned.
The purpose of dragging the img grid is to be able to change the 'imageorder' index. On completion of the drag, the sortable library POSTS an 'imageorder' var by ajax to service.php and is received correctly. So rather than the original 0,1,2,3,4,5,6,7 order of the original, it sends a string like 2,1,0,3,4,5,7,6. Not too hard to grasp. After I switch the order the orderList var sent to service.php is always correct, but the array I end up sending to the db and setting as my session var becomes a little garbled in order after the second or third drag and I'm not quite sure why.
Code Examples and Comments
$_SESSION['selectedCsImages'] Array structure:
[0] => Array
(
[imagename] => "Title"
[imageorder] => 0
[imageid] => 43
)
[1] => Array
(
[imagename] => "Title"
[imageorder] => 1
[imageid] => 21
)
[2] => Array
(
[imagename] => "Title"
[imageorder] => 2
[imageid] => 3
)
etc...
Services.php extract:
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
// Turn the orderList posted into an array
$removeChars = array('"','[',']');
$orderList = str_replace($removeChars, "", $_POST['order']); // POST received fine.
$listArray = explode(",",$orderList);
// Retrieve the session array
$sorting = $_SESSION['selectedCsImages'];
/* My logic is that I compare the $sorting array to $listArray and reorder $sorting by 'imageorder' to match $listarray */
usort($sorting, function($a, $b) use ($listArray) {
return array_search($a['imageorder'], $listArray) - array_search($b['imageorder'], $listArray);
});
/* I now have a $sorting array that (sometimes, hence the problem) matches the order that the images had just been dragged into by the user. Typically, as I mentioned above, it's correct after the first drag, but not always after the second or third where it creates a new order that I can't see a pattern or logic in. */
/* Had there not been errors with the usort function, I (would) have a $sorting array in the order I want but with imageorder values referring to pre-sorting. I iterate through the array and set each key to 0, 1, 2, etc. so that I have an array in the correct order and with each imageorder correctly stating its place.*/
$i = 0;
foreach ($sorting as $key => $value) {
$sorting[$key]['imageorder'] = $i;
$i++;
}
/* The information is attempted to be sent to the db and, on success I update the session var */
// Database code (runs succesfully and updates the db as per the image orders found in the $sorting array)
$_SESSION['selectedCsImages'] = $sorting;
Debugging:
From debugging, it appears that something happens with the usort function when I call this page from ajax for the second or third time. Everything after this follows through fine and processes the correct or incorrect order as per expectations. The orderList var posted by sortable is correct each time. I'd provide a sample of the $sorted var after usort each time but it's as simple to describe it as the above array example in an order I didn't specify after dragging and I can't see a pattern in the seemingly random order it outputs.
From researching, I had thought that it was an issue with session vars being retained until the page is refreshed but it appears that the ajax call to services.php should refresh the $_SESSION['selectedCsImages'] var. I had also read that, perhaps, I was unknowingly using referenced array values and - as I source from a session var to a new array and, ultimately, save back to this session var from this array - I may have created some messy referencing feedback. However, I tried using $sorted = (array)clone(object)$_SESSION['selectedCsImages']; before attempting usort and the results didn't change.
PHP error logs are showing nothing.
Updates:
Per the suggestion of #Ayaou, I've checked the output of $listArray and am getting some unexpected results. I'd wrongly assumed that as the posted $orderList was correct, that the exploded array would not be a culprit.
Here's the output of print_r($listArray) after completing the following order swaps of 16 img elements: 1st with 2nd, 2nd last with last,6th with 7th:
1st and 2nd:
(
[0] => 1
[1] => 0
[2] => 2
[3] => 3
[4] => 4
[5] => 5
[6] => 6
[7] => 7
[8] => 8
[9] => 9
[10] => 10
[11] => 11
[12] => 12
[13] => 13
[14] => 14
[15] => 15
)
last and 2nd last:
(
[0] => 1
[1] => 0
[2] => 2
[3] => 3
[4] => 4
[5] => 5
[6] => 6
[7] => 7
[8] => 8
[9] => 9
[10] => 10
[11] => 11
[12] => 12
[13] => 13
[14] => 15
[15] => 14
)
6th with 7th:
(
[0] => 1
[1] => 0
[2] => 2
[3] => 3
[4] => 4
[5] => 6
[6] => 5
[7] => 7
[8] => 8
[9] => 9
[10] => 10
[11] => 11
[12] => 12
[13] => 13
[14] => 15
[15] => 14
)
I was progressing with the idea that $listArray would show a sequential 0,1,2,3,etc. each time with only the two swapped items showing order changes. As it's not, I'll look back again at $orderList and check if my sortable library is updating the orders it's obtaining correctly from the updated session var. Older order swaps are being retained somewhere along the chain where they shouldn't.
The solution is on your sortable form (on the front end), so instead of sending the imageorder on your 'order' post data, send the imageid index.
Then change your sort callback like this
//Use imageid index instead of imageorder
usort($sorting, function($a, $b) use ($listArray) {
return array_search($a['imageid'], $listArray) - array_search($b['imageid'], $listArray);
});

php mysql check if vendor has 3 low consecutive ratings

on my ratings table for my software i have 4 fields.
id autoincrement
rvid vendor id
ratedate date of rating
rating the actual numeric rating
I have done alot with it over the last few months but this time im stumped and i cant get a clear picture in my head of the best way to do this. What i am trying to do is find out if the vendor has had 3 low 'consecutive' ratings. If their last three ratings have been < 3 then i want to flag them.
I have been playing with this for a few hours now so i thought i would ask (not for the answer) but for some path direction just to push me forward, im stuck in thought going in circles here.
I have tried GROUP BY and several ORDER BY but those attempts did not go well and so i am wondering if this is not a mysql answer but a php answer. In other words maybe i just need to take what i have so far and just move to the php side of things via usort and the like and do it that way.
Here is what i have so far i did select id as well at first thinking that was the best way to get the last consective but then i had a small breakthrough that if they have had 3 in a row the id does not matter, so i took it out of the query.
$sql = "SELECT `rvid`, `rating` FROM `vendor_ratings_archive` WHERE `rating` <= '3' ORDER BY `rvid` DESC";
which give me this
Array
(
[0] => Array
(
[rvid] => 7
[rating] => 2
)
[1] => Array
(
[rvid] => 5
[rating] => 1
)
[2] => Array
(
[rvid] => 5
[rating] => 0
)
[3] => Array
(
[rvid] => 5
[rating] => 3
)
)
this is just just samples i tossed in the fields, and there are only 4 rows here where as in live it will be tons of rows. But basically this tells me that these are the vendors that have low ratings in the table. And that is where i get stumpted. I can only do one sort in the query so that is why i am thinking that i need to take this and move to the php side to finish it off.
I think i need to sort the elements by rvid with php first i think, and then see if three elements in a row are the same vender (rvid).
Hope that makes sense. My brain hurts lol...
update - here is all of the table data using *
Array
(
[0] => Array
(
[id] => 7
[rvid] => 7
[ratedate] => 2016-05-01
[rating] => 2
)
[1] => Array
(
[id] => 8
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 1
)
[2] => Array
(
[id] => 6
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 0
)
[3] => Array
(
[id] => 5
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 3
)
)
Here's one way you can begin approaching this - completely in SQL:
Get the last rating for the vendor. ORDER BY date DESC, limit 1.
Get the second to last rating for the vendor. ORDER BY date DESC, limit 1, OFFSET 1.
Then write a query that does a LEFT join of the first two tables. You will have a dataset that has three columns:
vendor id
last rating
second to last rating
Then you can write an expression that says "if column1 is <3 and column2 < 3, then this new column is true"
You should be able to extend this to three columns relatively easily.
Here is what a came up with to solve this riddle. I think explaining it on here helped as well as Alex also helped as he keyed my brain on using the date. I first started looking at using if statment inside of the query and actually that got my brain out of the box and then it hit me what to do.
It is not perfect and certainly could use some trimming to reduce the code, but i understand it and it seems to work, so that is par for me on this course.
the query...
$sql = "SELECT `rvid`, `ratedate`,`rating` FROM `vendor_ratings_archive` WHERE `rating` <= '3' ORDER BY `ratedate`, `rvid` DESC";
which gives me this
Array
(
[0] => Array
(
[rvid] => 7
[ratedate] => 2016-05-01
[rating] => 2
)
[1] => Array
(
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 1
)
[2] => Array
(
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 0
)
[3] => Array
(
[rvid] => 5
[ratedate] => 2016-05-01
[rating] => 3
)
)
notice how vendor (rvid) 5 is grouped together which is an added plus.
next a simple foreach to load a new array
foreach($results as $yield)
{
$rvidarray[] = $yield['rvid'];
}//close foreach
which gives me this
Array
(
[0] => 7
[1] => 5
[2] => 5
[3] => 5
)
then we count the array values to group dups
$rvidcounter = array_count_values($rvidarray);
which results in this
Array(
[7] => 1
[5] => 3
)
so now vender 7 as 1 low score and vendor 5 has 3 low scores and since they were already sorted by date i know that its consecutive. Well it sounds good anyway lol ")
then we create our final array with another foreach
foreach($rvidcounter as $key => $value)
{
//anything 3 or over is your watchlist
if($value > 2)
{
$watchlist[] = $key; //rvid number stored
}
}//close foreach
which gives me this
Array
(
[0] => 5
)
this was all done in a service function. So the final deal is everyone in this array has over 3 consecutive low ratings and then i just use a returned array back in my normal php process file and grab the name of each vender by id and pass that to the html and print out the list.
done...
please feel free to improve on this if you like. I may or may not use it because the above code makes sense to me. Something more complicated may not make sense to me 6 mos from now lol But it would be interesting to see what someone comes up with to shorten the process a bit.
Thanks so much and Happy Coding !!!!!
Dave :)
You could do it in SQL like that:
SET #rvid = -1;
SELECT DISTINCT rvid FROM
(
SELECT
rvid,
#neg := rating<3, /* 0 or 1 for addition in next line */
#count := IF(#rvid <> rvid , #neg, #count+#neg) AS `count`, /* set or add */
#rvid := rvid /* remember last row */
FROM
testdb.venrate
ORDER BY
rvid, datetime desc
) subq
WHERE count>=3
;
You set a variable to a non existing id. In each chronologically sorted row you check if rating is too low, that results in 1 (too low) or 0 (ok). If rvid is not equal to the last rvid, it means a new vender section is beginning. On begin of section set the value 0 or 1, else add this value. Finally store the current row's rvid for comparison in next row process.
The code above is looking for 3 consecutive low ratings (low means a value less than 3) over all the time.
A small modification checks if all the latest 3 ratings has been equal to or less than 3:
SET #rvid = -1;
SELECT DISTINCT
rvid
FROM
(
SELECT
rvid,
#high_found := rating>3 OR (#rvid = rvid AND #high_found) unflag,
#count := IF(#rvid <> rvid , 1, #count+1) AS `count`,
#rvid := rvid /* remember last row */
FROM
testdb.venrate
ORDER BY
rvid, datetime desc
) subq
WHERE count=3 AND NOT unflag
;

How to take value from First array and generate second array and put the second array in the first array?

I have tried many ways to do this but no luck. I'm trying to take value from First array and generate second array and put the second array in the first array.
The code that I have now, generate the first array, in this array I have column called prereq_id I need to take this value and match it with courses table to bring its information in the courses table course_id=prereq_id. Any help would be highly appreciated
The array output is like this right now
[course_id] => 2
[curriculum_id] => 1
[set_number] => 0
[course_code] => GCIS 516
[course_name] => Data-Centric Concepts and Methods
[credits] => 3
[semester_ava] => 2
[prereq_id] => 10
[set] => 3
php
$result2 = $mysqli->query("SELECT *
FROM curriculumcourses
INNER JOIN courses ON curriculumcourses.course_id = courses.course_id
LEFT JOIN prerequisites ON courses.course_id=prerequisites.course_id
WHERE curriculum_id='$ids' ");
?>
<?php
for ($x = 1; $x <= $mysqli->affected_rows; $x++) {
$rows[] = $result2->fetch_assoc();
}
echo "<pre>";
print_r($rows);
echo "</pre>";
The result I need look like this
[course_id] => 2
[curriculum_id] => 1
[set_number] => 0
[course_code] => GCIS 516
[course_name] => Data-Centric Concepts and Methods
[credits] => 3
[semester_ava] => 2
[prereq_id] => 10
[set] => 3
[course_code] => GCIS 508
[course_name] =>Database Management Systems
[credits] => 3
[semester_ava] => 1

php dynamically create multi dimensional array

I am writing a php script to extract some data from a MYSQL db, then I want to take that data and store it into a two dimensional array. Thinking of it normally, if I use code like this
$test = array();
$test[0]=array();
$test[0]['hello']='hello';
$test[1]=array();
$test[1]['hello']='hello';
$test[2]=array();
$test[2]['hello']='hello';
print_r($test);
the output will be:
Array ( [0] => Array ( [hello] => hello ) [1] => Array ( [hello] => hello ) [2] =>
Array ( [hello] => hello ) )
which is how I want my output to be
so this is what I do in my script
So basically in my database I have table with standings for a women's league and the columns are
team_name, played, won, drawn, lost, for, against, points
All the connections have been taken care of successfully, below is my query
$get_ladies_query = "SELECT
`team_name`, `played`, `won`, `drawn`, `lost`, `for`, `against`, `points`
FROM `standings_ladies` order by pos";
An important point to not before I show the next code is that, there are 2 other standings tables, men_senior and men_intermediate with the same structure but obviously only the data changes, below are the two queries just incase
$get_mens_inter_query = "SELECT
`team_name`, `played`, `won`, `drawn`, `lost`, `for`, `against`, `points`
FROM `standings_men_inter` order by pos";
$get_mens_senior_query = "SELECT
`team_name`, `played`, `won`, `drawn`, `lost`, `for`, `against`, `points`
FROM `standings_men_senior` order by pos";
Now I create 3 arrays which I want to hold standings seperately for the ladies, mens senior, mens intermediate
$standings_ladies = array();
$standings_men_inter = array();
$standings_men_senior = array();
The data I want displayed in the array is like so
array(0=>array(team_name,wins,drawn,lost,for,against,points)
1=>array(team_name,wins,drawn,lost,for,against,points)) and so on
Now since I wanted to create the multidimensional arrays of standings for all 3 categories, I could have run the queries in 3 separate while loops altough I thought, I could accomplish the same result in 1 and i felt it would help improve performance. If its better to use 3 while loops, please let me know, what I tried is below.
//I run the 3 queries and store them in the given variables
$result_mens_senior = mysqli_query($link,$get_mens_senior_query);
$result_mens_inter = mysqli_query($link,$get_mens_inter_query);
$result_ladies= mysqli_query($link, $get_ladies_query);
//I want to create 1 while loop so based of the results returned from the 3
//queries so based on the results returned from the 3 queries,
//I get the max number of times I want the query to run
$ladies_boundary = mysqli_num_rows($result_ladies);
$mens_senior_boundary = mysqli_num_rows($result_mens_senior);
$mens_inter_boundary = mysqli_num_rows($result_mens_inter);
$max_size = max(array($ladies_boundary,$mens_senior_boundary,$mens_inter_boundary));
//set an index to start from 0
$index = 0;
//I will only show the example for 1 of the arrays but you get an idea
that this issue will occur for all
while ($index < $max_size)
{
//first, everytime the loop is entered, we need the next row to be fetched
$standings_men_inter_table = mysqli_fetch_assoc($result_mens_inter);
$standings_ladies_table = mysqli_fetch_assoc($result_ladies);
//there is a high chance that the other two tables return a different row size
//so its best to check that we do not go beyond
if($index < $mens_senior_boundary)
{
//we fetch the rows every time we enter the block
$standings_men_senior_table = mysqli_fetch_assoc($result_mens_senior);
//then, this is how I attempt at creating the 2 dimensional array
array_push($standings_men_senior, array(
$standings_men_senior_table['team_name'],
$standings_men_senior_table['played'],
$standings_men_senior_table['won'],
$standings_men_senior_table['drawn'],
$standings_men_senior_table['lost'],
$standings_men_senior_table['for'],
$standings_men_senior_table['against'],
$standings_men_senior_table['points']));
}
//incrementing index each time the loop runs
$index++;
}
Then finally, I just want to print what I think is the array but get this, attached image, hope you can see it clearly
Just to investigate even further, every time, the 'if' block is entered, I just commented everything out and just put this to see what was being returned
if($index < $mens_senior_boundary)
{
print_r(mysqli_fetch_assoc($result_mens_senior));
}
The output I got was almost 90% what I need
Array
([team_name] => Morley Gaels [played] => 8 [won] => 6 [drawn] => 2
[lost] => 0 [for] => 110 [against] => 83 [points] => 14 )
Array ( [team_name] => Southern Districts [played] => 8 [won] => 3 [drawn] => 2
[lost] => 3 [for] => 104 [against] => 98 [points] => 8 )
Array ( [team_name] => St Finbarrs [played] => 8 [won] => 3 [drawn] => 2
[lost] => 3 [for] => 107 [against] => 99 [points] => 8 )
Array ( [team_name] => Western Shamrocks [played] => 8 [won] => 3 [drawn] => 0
[lost] => 5 [for] => 96 [against] => 88 [points] => 6 )
Array ( [team_name] => Greenwood [played] => 8 [won] => 1 [drawn] => 1
[lost] => 9 [for] => 82 [against] => 109 [points] => 3 )
What I need is for example:
Array(0=>Array
([team_name] => Morley Gaels [played] => 8 [won] => 6 [drawn] => 2
[lost] => 0 [for] => 110 [against] => 83 [points] => 14 )
1=>Array
([team_name] => Southern Districts [played] => 8 [won] => 3 [drawn] => 2
[lost] => 3 [for] => 104 [against] => 98 [points] => 8 )..... so on);
My questions are
What is wrong with my code and what is the correct way to dynamically create
multidimensional arrays in php ?
Is there something I have not understood about how mysql_fetch_assoc works and how it returns ?
Anything to improve, anything I am doing wrong ?
I appreciate your time, than you for reading it, I tried to be as detailed as I can about what I have tried.
Thank You.
Try this
After you do this:
$result_mens_senior = mysqli_query($link,$get_mens_senior_query);
$result_mens_inter = mysqli_query($link,$get_mens_inter_query);
$result_ladies= mysqli_query($link, $get_ladies_query);
just do this
while ($standings_men_senior[] = mysqli_fetch_assoc($result_mens_senior)){}
while ($standings_men_inter[] = mysqli_fetch_assoc($result_mens_inter)){}
while ($standings_ladies[] = mysqli_fetch_assoc($result_ladies)){}
Basically all of the posted code should be able to be replaced with:
<?php
$ladies_query = "SELECT `team_name`, `played`, `won`, `drawn`, `lost`, `for`, `against`, `points`
FROM `standings_ladies` order by pos";
$inter_query = "SELECT `team_name`, `played`, `won`, `drawn`, `lost`, `for`, `against`, `points`
FROM `standings_men_inter` order by pos";
$senior_query = "SELECT `team_name`, `played`, `won`, `drawn`, `lost`, `for`, `against`, `points`
FROM `standings_men_senior` order by pos";
$ladies_stmt = mysqli_query($link, $ladies_query) || die ("Couldn't get Ladies"); // reminds me of high school
$inter_stmt = mysqli_query($link, $inter_query) || die ("Couldn't get Inter");
$senior_stmt = mysqli_query($link, $serior_query) || die ("Couldn't get Seniors");
$standings_men_senior = array();
$standings_men_inter = array();
$standings_ladies = array();
while ($row = mysqli_fetch_assoc($senior_stmt)){
$standings_men_senior[] = $row;
}
while ($row = mysqli_fetch_assoc($inter_stmt)){
$standings_men_inter[] = $row;
}
while ($row = mysqli_fetch_assoc($ladies_stmt)){
$standings_ladies[] = $row;
}
Don't try to put everything in a single loop, it significantly reduces your code clarity and will give you little to no gain in performance, there is a term for this and it's called micro-optimization, and you should never do it unless it is really necessary (a bottleneck on a large site).
Now, what I suggest to you is to remake your loop and make it as clear as possible as to how data is manipulated.
The most important thing in your case is to debug, print_r the content of your arrays on every step of the process to check what it contains, from the database to the end of your code, you will find where the problem is.

Filter two multidimensional arrays based on key matches, but each array has different structure - Output to new merged array

I am trying to extract only array items that match on specific fields and then I need to merge the two into one array only containing the data I need.
I have two arrays, and their structure is like below. Only product_count s where CATEGORY_ID of Array #1 match the Key of Array #2 should be the output.
Array #1: - Many of Array #1 CATEGORY_IDs will not exist in Array #2 key field.
0 => Array (4)
0 => 3
CATEGORY_ID => 10
1 => 1
product_count => 8
1 => Array (4)
0 => 4
CATEGORY_ID => 111
1 => 6
product_count => 109
...
Array #2:
10 => Category Name 1
110 => Category Name 2
8 => Category Name 3
109 => Category Name 4
111 => Category Name 5
3 => Category Name 6
132 => Category Name 7
...
Final Output should look something like: and I might be going about this all wrong, so I am open to any suggestions..
10 => [0] => Category Name 1
[1] => 8 // product_count
111 => [0] => Category Name 5
[1] => 109 // product_count
...
I am running a foreach() to extract product counts per category. As you can see my two arrays reflect this by the data.
You'd have to do a foreach loop, I believe:
$new_array = array();
foreach($array1 as $part) {
$new_array[$part["CATEGORY_ID"]] = array( $array2[$part["CATEGORY_ID"]], $part["product_count"] );
}
I think I got the gist of what you want. I don't think there is an actual PHP function to do what you want, either.

Categories