I'm sure that the title is a bit of vague, but i hope that the example will explain the issue better.
So, I have an array that contains a list of 40 results. In each of the results, there is a timestamp, which i translate to a specific day, like "monday" and a temperature. The thing is that, there can be up to 8 time periods in one day. And a temperature for each period. I somehow have to determine how to asign a maximum temperature for a specific day based on all of the temperatures related to that day.
So, the array looks something like this:
array (size=40)
0 =>
'dt' => int 1530802800
'main' =>
'temp' => float 29.14
1 =>
'dt' => int 1530813600
'main' =>
'temp' => float 25.63
...
And what i would like to achieve something like this:
array
monday => 27.65
tuesday => 24.65
...
I'm able to create two separate arrays that hold all the days and all of the temperatures, but i'm not sure how to bind all of the temperatures related to a specific day, since i can have the same day appear in that array up to 8 times, and then calculate the highest temperature for that day.
I have something like:
0 => monday
1 => monday
2 => monday
3 => tuesday
and another array is:
0 => 23.56
1 => 34.66
2 => 12.44
3 => 34.44
What i would like is to at least have something like this
monday => array(
0 => 23.56
1 => 34.66
2 => 12.44
),
tueasday => array(
0 => 34.56
1 => 34.66
2 => 13.44
)
...
Hope that was clear enough.
Any help is appreciated.
Thanks.
Starting from your original array (not the two separate ones). Get the day from the timestamp and assign that as the key of the result. Check if the current value is less and if so replace with the new one:
foreach($array as $values) {
$day = strtolower(date('l', $values['dt']));
if(!isset($result[$day]) || $result[$day] < $values['main']['temp']) {
$result[$day] = $values['main']['temp'];
}
}
You could also create an array keyed by the day with all temperatures:
foreach($array as $values) {
$day = strtolower(date('l', $values['dt']));
$result[$day][] = $values['main']['temp'];
}
Then compute the maximums for each day:
$max = array_map('max', $result);
It looks like the concept you're missing to accomplish this is dynamically constructing an array from keys.
If you iterate your original array, convert the timestamp to a day. You've said you already know how to do that. Then use that day as the key to construct your result array.
foreach ($data as $measurement) {
$day = however_you_convert($measurement['dt']);
// ↓ defines the group
$result[$day][] = $measurement['main']['temp'];
// ↑ adds the value to an array under that group
}
That will convert your data to the grouped structure shown in the last code block in your question. From there, you can use sort or max to get the highest value.
If you don't need the sets of values, you can just keep track of the max value as you go, like this other answer shows.
now that you have this:
$days = ["0" => "monday",
"1" => "monday",
"2" => "monday",
"3" => "tuesday"];
$temps = [
0 => 23.56,
1 => 34.66,
2 => 12.44,
3 => 34.44
];
you can do this:
$result = [];
foreach($days as $key => $day){
if(!isset($result[$day]))
$result[$day] = $temps[$key];
if($temps[$key] > $result[$day])
$result[$day] = $temps[$key];
}
var_dump($result);
output:
array(2) {
["monday"]=>
float(34.66)
["tuesday"]=>
float(34.44)
}
Hope it helps you arrive at a optimal solution.
Based of what you show us :
$days = array(
0 => 'monday',
1 => 'monday',
2 => 'monday',
3 => 'tuesday'
);
$temp = array(
0 => 23.56,
1 => 34.66,
2 => 12.44,
3 => 34.44
);
If you are sure that you have 2 array with the same size :
$new_array = array();
foreach ($days as $key=> $day) {
$new_array[$day][] = $temp[$key];
}
var_dump($new_array);
The output is :
array (size=2)
'monday' => array (size=3)
0 => float 23.56
1 => float 34.66
2 => float 12.44
'tuesday' => array (size=1)
0 => float 34.44
Now if you want an array with the day and the max temp of each day :
$result = array();
foreach($new_array as $day => $temp_array) {
$result[$day] = max($new_array[$day]);
}
var_dump($result);
The output is :
array (size=2)
'monday' => float 34.66
'tuesday' => float 34.44
There is maybe a better way to achieve it but according to your question and what you ask for it should do the job, I hope it helps !
Related
I am building a Logistic Regression platform in PHP. The following code snippet works fine when there is only one feature inside the data frame. For example a CSV file like this:
"sample","language"
"Hello, how are you?","english",
"Je voudrais une boîte de chocolats.","french"
...
However, when I try to train the AI with 2 features based on the titanic survival rate (hypothesis: Does the amount of siblings and spouses effect the survival rate) with a data frame like this:
"SibSp","Parch","Survived",
"1", "1", "1",
"3", "3", "1",
"4", "1", "0"
...
I am getting this error:
Phpml\Exception\InvalidArgumentException Size of given arrays does not match
My code snippet looks like this, $request->features holds the amount of features this data frame has since features +1 will hold the actual outcome (1 = survived, 0 = died):
$dataset = new CsvDataset($file, (int) $request->features);
$vectorizer = new TokenCountVectorizer(new WordTokenizer());
$tfIdfTransformer = new TfIdfTransformer();
$samples = [];
for($i = 0; $i <= $request->features -1; $i++):
foreach ($dataset->getSamples() as $sample):
$samples[$i][] = $sample[$i];
endforeach;
endfor;
for($i = 0; $i <= count($samples) -1; $i++):
$vectorizer->fit($samples[$i]);
$vectorizer->transform($samples[$i]);
$tfIdfTransformer->fit($samples[$i]);
$tfIdfTransformer->transform($samples[$i]);
endfor;
$dataset = new ArrayDataset($samples, $dataset->getTargets()); # This throws the error
I am using PHP-AI/PHP-ML and here is an example of how the AI works with the data frame with only 1 feature provided by the framework.
I understand the error, $dataset->getTargets() only holds 1 array, where as $samples holds 2 arrays. However, this has got me stumped since that is how it should be (in theory).
I am storing the classifier (or trained AI) as a serialised object inside my database once it has been trained to remember its trained state. Everything works fine when I only use a data frame with one feature. Does anyone have experience using PHP-AI within the PHP-ML library that can help?
How can I increase the amount of features inside PHP-AI?
Update to show what values my arrays hold:
$samples looks like this (array of siblings, array of spouses):
array ( 0 => array ( 0 => array ( ), 1 => array ( ), 2 => array ( ), 3 => array ( ), 4 => array ( ), 5 => array ( ), 6 => array ( ), 7 => array ( ), ), 1 => array ( 0 => array ( ), 1 => array ( ), 2 => array ( ), 3 => array ( ), 4 => array ( ), 5 => array ( ), 6 => array ( ), 7 => array ( ), ), )
$dataset->getTargets() looks like this (survived or died):
array ( 0 => '1', 1 => '1', 2 => '0', 3 => '1', 4 => '0', 5 => '0', 6 => '1', 7 => '1', )
I believe that the $samples array should be 1 array holding child arrays of [SibSp, Spous]. I cannot think how to re-organise the array to be like this.
After fiddling around with the code and researching the error and how to get around it - I realised that the $samples data should be expressed as
Array [ 0 => [SibSp, Spous], 1 => [SibSp, Spous], ... ]
So by re-fiddling the data like so:
$result = [];
foreach($samples as $arr) {
foreach($arr as $k => $v) {
$result[$k][] = $v;
}
}
I can achieve this desired outcome. I still had to push the samples into the vectorizer as $sample but the final Dataset had to be re-fiddled:
for($i = 0; $i <= count($samples) -1; $i++):
$vectorizer->fit($samples[$i]);
$vectorizer->transform($samples[$i]);
$tfIdfTransformer->fit($samples[$i]);
$tfIdfTransformer->transform($samples[$i]);
endfor;
$dataset = new ArrayDataset($result, $dataset->getTargets());
This seems the oldest question in the book with hundreds of resources available, but so far each solution I have tried has not solved my problem. I'm hoping you can help.
I'm trying to display a graph that displays the last 31 days of data. The outputted array looks like this:
$data[
0 =>
'day' => 10,
'amount' => 5,
'count' => 2
1 =>
'day' => 16,
'amount' => 4,
'count' => 2
2 =>
'day' => 21,
'amount' => 16,
'count' => 1
3 =>
'day' => 11,
'amount' => 0,
'count' => 0
4 =>
'day' => 12,
'amount' => 0,
'count' => 0
]
Essentially this array is composed of two parts. The first 3 inner arrays are days that contain amounts and counts, the remaining 27 are any unaccounted for days with their amounts and counts set to 0. So for example $data[5] will be day 13 and $data[21] day 31. $data[22] will then equal day 1, going up to day 9 thus therefore showing the last 31 days.
In addition there is an ordered array of the days we want to output.
$days[
0 =>
'day' => 10
1 =>
'day' => 11
2 =>
'day' => 12
...
30 =>
'day' => 9
]
I have tried the below but whilst $data is now ordered, it's essentially just a replica of $days and loses the other values held in $data.
$data = array_uintersect($days, $data, array($this, 'compare_days'));
function compare_days($order, $array) {
return strcmp($order['day'], $array['day']);
}
What's up? How can I sort $data so that it retains the data and orders it as desired in $days?
Simply use uasort as
uasort($data, function($a,$b) use ($days){
foreach($days as $value){
if($a['day'] == $value['day']){
return 0;
break;
}
if($b['day'] == $value['day']){
return 1;
break;
}
}
});
Demo
You can use this:
foreach ($data as $key => $row) {
$days[$key] = $row['day'];
$amount[$key] = $row['amount'];
}
array_multisort($days, SORT_ASC, $amount, SORT_ASC, $data);
print_r($data);
Struggling with concept of an associative array that maps userIDs to partIDs and re-order quantity for the part.
We have bunch of parts that I need to re-order, but I must keep track of which user needs what parts re-purchased for them. The list of UserIDs comes from one table, then the inventory_used comes from another table.
Suppose a list like this:
Example One:
UserID PartID Qty_Used
1 3 2
1 4 7
2 1 4
2 4 3
3 3 5
After creating an array with the above information, I must create a re-order form (table) for the parts. Therefore, ignoring the userID, group them by the partID, and sum up the total Qty (per part). The re-order table should look something like this:
Example Two:
PartID Qty_to_Reorder
1 4
3 7
4 10
I know I'm going to take a ton of downvotes for failing to show code, but I can't wrap my mind around this seemingly simple problem. (This is for my office, not a school project).
How do I:
(1) Structure the first array (what would the loop to create it look like?), and then
(2) Loop through that array to summarize/group partIDs => Qty for re-order report, as per 2nd example above?
For the first loop, i was thinking of something like this:
Loop through UserIDs {
Loop through PartIDs {
$arrReorder[UserID][PartID] = Qty_Used;
}
}
Is that correct? How would I loop through $arrReorder to sum-up the qty used for each partID, and get the re-order report (example 2)?
SELECT SUM(Qty_Used) AS total FROM mytable WHERE PartID=3
PS: Using PHP
<?php
$data = array();
$data[] = array("UserID" => 1, "PartID" => 3, "Qty_Used" => 2);
$data[] = array("UserID" => 1, "PartID" => 4, "Qty_Used" => 7);
$data[] = array("UserID" => 2, "PartID" => 1, "Qty_Used" => 4);
$data[] = array("UserID" => 2, "PartID" => 4, "Qty_Used" => 3);
$data[] = array("UserID" => 3, "PartID" => 3, "Qty_Used" => 5);
$PartID = 3;
$sum = 0;
foreach ($data as $arr) {
if ($arr['PartID'] == $PartID)
$sum += $arr['Qty_Used'];
}
echo $PartID."\t".$sum."\r\n";
?>
Arrays have a key and value where the value can be another array. Determine what is the key value.
I am assuming you have users consuming parts and you have to re-order the parts from your supplier. No where the user is a customer and the user has a auto re-order policy.
What triggers a reorder? If re-order quantity is 10 and user uses 1, there should be nine in stock.
Create the partsUsed array elements, This is a bit tricky:
$partsUsed[$part][] = array($qtyUsed,$user);
The reason the empty brackets [] is there is to allow duplicate part numbers in the parts used, and still key part as the key.
The value is an array to key the association between user and parts.
what you end up with is a sequentially numbered secondary key where the value is just a throw away, but allows duplicate part numbers.
$partsUsed[3][] = array(2,1);
$partsUsed[4][] = array(7,1);
$partsUsed[1][] = array(4,2);
$partsUsed[4][] = array(3,2);
$partsUsed[3][] = array(5,5);
ksort($partsUsed); // sorts key on part number
var_export($partsUsed);
Result array (var_export):
array (
1 =>
array (
0 =>
array (
0 => 4,
1 => 2,
),
),
3 =>
array (
0 =>
array (
0 => 2,
1 => 1,
),
1 =>
array (
0 => 5,
1 => 5,
),
),
4 =>
array (
0 =>
array (
0 => 7,
1 => 1,
),
1 =>
array (
0 => 3,
1 => 2,
),
),
)
Notice part 3 and 4 have two arrays.
$reorder[1] = 4 ;
$reorder[2] = 7 ;
$reorder[4] = 10 ;
var_export($reorder);
Result array:
array (
1 => 4,
2 => 7,
4 => 10,
)
Now not sure how to determine what gets reordered and how many.
I'll show how to get the values:
foreach($partsUsed as $part => $value){
foreach($value as $k => $v){
echo "Part $part: Qty:$v[0] User:$v[1]\n";
$qtyUsed[$part] += $v[1];
}
}
var_export($qtyUsed);
Outputs:
Part 1: Qty:4 User:2
Part 3: Qty:2 User:1
Part 3: Qty:5 User:3
Part 4: Qty:7 User:1
Part 4: Qty:3 User:2
$qtyUsed
array (
1 => 2,
3 => 4,
4 => 3,
)
foreach ($qtyUsed as $part => $qty){
$order[$part] = $reorder[$part];
}
var_export($order);
Result $order:
array (
1 => 4,
3 => 7,
4 => 10,
)
I i'm developing php application. I have used Google Chart API for display charts.
I have select and returned necessary data for chart.
I got following array as my output.
print_r($output);
//Out put
Array
(
[0] => Array
(
[month] => April
[sec_id] => 2
[sec_name] => Commerce
[count] => 1
)
[1] => Array
(
[month] => June
[sec_id] => 2
[sec_name] => Commerce
[count] => 3
)
[2] => Array
(
[month] => July
[sec_id] => 2
[sec_name] => Commerce
[count] => 1
)
[3] => Array
(
[month] => August
[sec_id] => 4
[sec_name] => Science
[count] => 3
)
[4] => Array
(
[month] => August
[sec_id] => 3
[sec_name] => Maths
[count] => 2
)
[5] => Array
(
[month] => August
[sec_id] => 1
[sec_name] => Art
[count] => 2
)
[6] => Array
(
[month] => August
[sec_id] => 2
[sec_name] => Commerce
[count] => 2
)
)
print_r(json_encode($output)); // return above array as output
I request above data using ajax ( data type is JSON)
I want to return data as bellow to generate google chart.
[
['Month', 'Art', 'Commerce', 'Maths', 'Sience'],
['April', '', 2, '', ''],
['June', '', 3, '', ''],
['July', '', 1, '', ''],
['August', 2, 2, 3, 3]
]
I tried this this code
$output = array();
$output[0] = array('Month', 'Art', 'Commerce', 'Maths', 'Science');
foreach($records as $key=> $record){
$art =''; $commerce =''; $maths=''; $science='';
if($record['sec_id'] == 1){
$art = $record['count'];
}else if($record['sec_id'] == 2){
$commerce = $record['count'];
}else if($record['sec_id'] == 3){
$maths = $record['count'];
}else if($record['sec_id'] == 4){
$science = $record['count'];
}
$output[++$key] = array(0 => $record['month'], 1 => $art, 2 => $commerce, 3 => $maths, 4 => $science);
}
function super_unique($array){
$result = array_map("unserialize", array_unique(array_map("serialize", $array)));
foreach ($result as $key => $value){
if ( is_array($value)){
$result[$key] = super_unique($value);
}
}
return $result;
}
$output = super_unique($output);
Out put was
[["Month","Art","Commerce","Maths","Science"],["April","","1"],["June","","3"],["July","","1"],{"0":"August","1":"","4":"3"},{"0":"August","1":"","3":"2"},["August","2",""],["August","","2"]]
This is pretty straightforward to loop through and reorganize, particularly since your sec_ids match up nicely with the array indices.
Example:
$temp = array();
$output = array(
array('Month', 'Art', 'Commerce', 'Maths', 'Science')
);
foreach ($records as $record) {
$month = $record["month"];
$sec_id = $record["sec_id"];
$count = $record["count"];
if (!isset($temp[$month])) {
$temp[$month] = array_fill(0, 5, '');
}
$temp[$month][0] = $month;
$temp[$month][$sec_id] += $count;
}
$output = array_merge($output, array_values($temp));
echo json_encode($output);
Output:
[["Month","Art","Commerce","Maths","Science"],["April","",2,"",""],["June","",3,"",""],["July","",1,"",""],["August",2,2,2,3]]
Let's rethink your algorithm. As you go through each element in records, we need to ask two things: what data are we pulling out and what do we want to do with it?
The first question is simple: we're just pulling out the value 'count'.
The second question is going to determine our algorithm. What we want to do is take that 'count' value, and stick it a particular spot in our ourpur array.
Looking at the output array as a table, we can see that the desired position of 'count' is determined by the 'month' field (which determines the row) and by the 'sec_id'/'sec_name' fields (which determine the column). So what you want your loop to look like is this...
foreach($records as $record)
{
$output[$record['month']][$record['sec_id']] = $record['count']
}
The first caveat to this is that for each unique month, you do still need to create and initialize the sub-array, and you must do it only once. So, the loop becomes.
foreach($records as $record)
{
if(!is_array($output[$record['month']]))
$output[$record['month']] = array(0 => $record['month'], 1 => '', 2 => '', 3 => '', 4 => '');
$output[$record['month']][$record['sec_id']] = $record['count']
}
Finally, we used the actual month name as the keys in the top-level array. To comply with the numeric-only keys specified in your desired output, we can ditch those keys with the following piece of code.
$output = array_values($output)
If I'm right in thinking you were trying to use super_unique() to combine rows with the same month, that's not what it was doing at all. Firstly, array_unique() doesn't combine rows, it eliminates duplicates. Since you were comparing serialized rows, rather than just looking at the month field, none of your rows were duplicates, so that function was doing nothing. Furthermore, since several of your array fields were set to '', the serialize/unserialize process was actually causing those fields to get dropped, which is why you were ending up with sub-arrays of less than five elements, and with associative keys.
This question already has answers here:
Add 2 values to 1 key in a PHP array
(7 answers)
Closed last month.
I have array
array
0 =>
array
2 => int 50000
1 =>
array
2 => int 30000
2 =>
array
1 => int 25000
3 =>
array
1 => int 20000
4 =>
array
1 => int 10000
I need to create array the result is:
array
2 => int 50000
2 => int 30000
1 => int 25000
1 => int 20000
1 => int 10000
Thank for all.
sorry, my english very bad :(
PHP doesn't allow arrays to have the same keys. This will show how php will handle a foreach loop wich is rewriting the array into a new one with desired key and value
$array = array(
0 =>
array(
2 => 50000),
1 =>
array(
2 => 30000),
2 =>
array(
1 => 25000),
3 =>
array(
1 => 20000),
4 =>
array(
1 => 10000)
);
$new_array = array();
foreach($array as $data)
{
foreach($data as $key => $val)
{
$new_array[$key] = $val;
}
}
var_dump($new_array);
This will output
array(2) {
[2]=>
int(30000)
[1]=>
int(10000)
}
Live Sample
As you can see keys are overwritten on each loop becuase they are identical and so are values, i think you can use the above function to have a one level array removing keys from $new_array
foreach($data as $key => $val)
{
$new_array[] = $val;
}
Live Sample
This does what you want (without preserving children keys, since you cannot have multiple elements with the same key):
$flat_array = array_map('current', $array);
Try here: http://codepad.org/1h7mKbqe