After pulling in some data from a mysql database saving it to a variable, I'm wondering if it's possible to "query" the variable instead of doing another request to the database? I realise I need to search an array of objects based on key and value. So here is an example of what I have.
<?php
[{"customer":1,"item":1,"bought_at":"2016-12-15 11:41:11"},
{"customer":2,"item":1,"bought_at":"2016-12-15 11:43:21"},
{"customer":3,"item":1,"bought_at":"2016-12-16 13:31:11"},
{"customer":1,"item":2,"bought_at":"2016-12-16 12:12:21"},
{"customer":1,"item":3,"bought_at":"2016-12-17 15:13:58"}]
?>
So lets say I need to search it based on the item number and the date (but not time) when the item was bought. The next step would be to return the result as another array of objects. So if I were to search for item 1 bought at 2016-12-15 it would return.
[{"customer":1,"item":1,"bought_at":"2016-12-15 11:41:11"},
{"customer":2,"item":1,"bought_at":"2016-12-15 11:41:21"},]
Is this possible? If so how would I go about doing it?
Regards
EDIT: The reason I originally asked this question was because I had a query inside a nested foreach loop which bothered me. It's a piece of code that builds up a a json table at the back-end to pass information to the front end to draw a google line graph. Also I changed the data slightly in my original question to try to make it easier to read. It's also built in Laravel. The complete code is pretty large so I'm just posting the nested foreach loops. The query is in the second loop and is given the variable $activations.
foreach ($timeRange as $time){
$temp = array();
$timeTwentyFour = date("G", strtotime($time));
$temp[] = array('v' => "Date(01,01,2000,$timeTwentyFour)");
foreach($data as $row){
$count = 0;
$activations = DB::table('customer_display')->where('display_id',$row->id)->where(DB::raw('DATE(created_at)'),$day)->get();
foreach($activations as $activation){
$timestamp = $activation->created_at;
$activationTime = explode(" ", $timestamp)[1];
if (strtotime($activationTime) >= strtotime($time) && strtotime($activationTime) < strtotime($time) + 3600){
$count++;
};
}
$temp[] = array('v' => (float) $count);
//The custom tooltip
$temp[] = array('v' => $time . ' ' . $row->location . '. ' . $count . ($count == 1 ? ' Activation' : ' Activations'));
}
$rows[] = array('c' => $temp);
}
If those are objects in an array and you only wanted the entries where item is 1 you could use array_filter;
$filtered = array_filter($items, function($item){
// only return objects where this is true
return $item->item == 1;
});
If you wanted only items purchased on the 15th use
return date('d', strtotime($item->bought_at)) == 15;
and if you want to see items 1 bought on the 15th you'd use
$filtered = array_filter($items, function($item){
return $item->item === 1
&& date('d', strtotime($item->bought_at)) == 15;
});
Also check out this answer on comparing dates for more information on how to better do that.
Another database request will be the better approach in most cases. A database is optimized for querying data. It can use indexes, etc. Well known databases like MySQL have a query optimalisation. Doing it by hand will be less efficient.
First downloading too much data and then use something like array_filter to linearly search through all the data is far less efficient than just querying the data with the search criteria in the query.
One way to do it is:
//Prepare statement once
$statement = $pdo->prepare("SELECT * FROM table WHERE item = ? AND bought_at = ?");
$statement->execute(array(1, "2016-12-15"));
foreach ($statement->fetchAll() as $array)
//Do something with $array
//reuse prepared statement with another selection criteria
$statement->execute(array(3, "2016-12-16"));
foreach ($statement->fetchAll() as $array)
//Do something with $array
Related
First, I have looked through dozens of similar questions/answers on this site an have not found any type of solution I could use or modify to use for this problem. There are a lot of things that come into play with this. I got close but it kept running out of memory or other resource so here I am.
I need to create a function that takes a set of arrays and returns all combinations with a specific set of rules. So to start I pull the arrays. There are 9 to start of all various lengths. 4 of the arrays are duplicate set of 4 other individual arrays. Heres how I pull the arrays to start, just so you have an idea of how the data looks.
$prodA1 = Products::where('type','a')->pluck('id')->toArray();
$prodA2 = Products::where('type','a')->pluck('id')->toArray();
$prodB1 = Products::where('type','b')->pluck('id')->toArray();
$prodB2 = Products::where('type','b')->pluck('id')->toArray();
$prodC1 = Products::where('type','c')->pluck('id')->toArray();
$prodC2 = Products::where('type','c')->pluck('id')->toArray();
$prodD1 = Products::where('type','d')->pluck('id')->toArray();
$prodD2 = Products::where('type','d')->pluck('id')->toArray();
$prodE = Products::where('type','e')->pluck('id')->toArray();
I need all set of arrays to be array('prodA1','prodA2','prodB1','prodB2','prodC1','prodC2','prodD1','prodD2','prodE') with the values being IDs bot the name of the array.
Each returned array must be unique
Each individual array can have as many as 96 ids but they all vary
I found the below function which if I add a take(5) to the above so it limits the output seems to produce at least all the combinations which I can then apply other rules to but it takes forever to run. This is the closest I have gotten though, there has to be a faster solution to this. Any help would be appreciated.
public function combinations($arrays, $i = 0) {
if (!isset($arrays[$i])) {
return array();
}
if ($i == count($arrays) - 1) {
return $arrays[$i];
}
// get combinations from subsequent arrays
$tmp = $this->combinations($arrays, $i + 1);
$result = array();
// concat each array from tmp with each element from $arrays[$i]
foreach ($arrays[$i] as $v) {
foreach ($tmp as $t) {
$result[] = is_array($t) ?
array_merge(array($v), $t) :
array($v, $t);
}
}
return $result;
}
EDIT:
The input wound be a set of 9 arrays with ids in them. For instance:
$prodA1 = array(1,2,3,4,5);
$prodA2 = array(1,2,3,4,5);
$prodB1 = array(6,7,8,9);
$prodB2 = array(6,7,8,9);
$prodC1 = array(10,11,12,13);
$prodC2 = array(10,11,12,13);
$prodD1 = array(14,15,16,17);
$prodD2 = array(14,15,16,17);
$prodE = array(18,19,20,21);
returns would look something like
array(1,2,6,7,10,11,14,15,18)
array(1,4,6,8,10,12,14,16,18)
so all the results would be unique, each one would contain 9 values made up of 2 prodA,2 prodB, 2 prodC, 2 prodD and 1 prodE
Hope that clears it up a little.
I have two arrays that each contains one mysql select from different days (24h interval). Arrays contains 1440 entries with another sub-array(temp1, temp2, temp3 and date). I tried foreach($array as $key=>$val) but I can't subtract $val with or from another, let's say, $val2. The most legit way to do this is (based on web search):
foreach($yesterdayValues as $key=>$val){
if(substr($key, 0, 5) == 'temp2')
$todayValues[$key] -= $val;
}
But it does not work.
The main idea is to subtract temp2 values from today with the same temp2 values from yesterday in order to see changes in temperature. And display them nicely.
EDIT : Something like that ?
$yesterdayValues['temp1'] = 18.145666122437;
$yesterdayValues['temp2'] = 19.1425666122437;
$yesterdayValues['temp3'] = 20.845666122437;
$difference = array();
$i = 2;
foreach($yesterdayValues as $key=>$val){
if(isset($yesterdayValues['temp'.$i])) {
$difference[$key] = (float)($val - $yesterdayValues['temp'.$i]);
}
$i++;
}
var_dump($difference);
show : array(2) { ["temp1"]=> float(-0.9969004898067) ["temp2"]=> float(-1.7030995101933) }
The answer is this (but it's kind of static for the moment):
for($i=0;$i<1440;$i++){
(float)$yesterdayValues[$i]['temp2'] = (float)$last24hourValues[$i]['temp2'] - (float)$yesterdayValues[$i]['temp2'];
}
There are 1440 entries in 24h, and the key cand be acessed manually in a simple for. Maybe this can work with foreach instead of simple for. I will check later.
may this work for you
$yesterdayValues = array(
array('temp1'=>18.145666122437,'temp2'=>14.875, 'temp3'=>18.104000091553, 'date'=>'2016-02-29 10:47:10'),
array('temp1'=>19.245666022437,'temp2'=>14.875, 'temp3'=>19.104000091553, 'date'=>'2016-02-29 11:47:10'),
array('temp1'=>20.145666122437,'temp2'=>14.875, 'temp3'=>20.104000091553, 'date'=>'2016-02-29 12:47:10'),
) ;
$todaysValues = array(
array('temp1'=>18.145666122437,'temp2'=>12.875, 'temp3'=>18.104000091553, 'date'=>'2016-02-29 10:47:10'),
array('temp1'=>19.145666122437,'temp2'=>14.075, 'temp3'=>19.104000091553, 'date'=>'2016-02-29 11:47:10'),
array('temp1'=>20.145666122437,'temp2'=>17.175, 'temp3'=>20.104000091553, 'date'=>'2016-02-29 12:47:10'),
) ;
$diffArr = array();
foreach ($yesterdayValues AS $key => $dataArr) {
$diffArr[$key] = (float)($dataArr['temp2'] - $todaysValues[$key]['temp2']);
}
need some help figuring this out, ive got some code like so
$q= $conn->query("SELECT * FROM table");
while($array2[] = $q->fetch_object());
array_pop($array2);
if(isset($array2[0]->DATE))
{
$date0 = $array2[0]->DATE;
}else{
$date0 = '';
}
if(isset($array2[1]->DATE))
{
$date1 = $array2[1]->DATE;
}else{
$date1 = '';
}
$data =('DATE1'= $date0,'DATE2'= $date1)
so you can see what the problem is , repeating stuff over and over , its horrible, im sure theres a clean way on doing it, but im not sure how, i tried using a for loop, but if 1 value was not set all other values would get the '' set to them so it didnt work... what i need to end up having is something that increments the 'DATE#' equal to the occurrences inside the $array2
so that if $array2 ranged from $array[0] to $array[4] then inside the $data array i would end up having DATE0 = $date0,DATE1 = $date1,DATE2 = $date2,DATE3 = $date3,DATE4 = $date4,DATE5 = $date5 hopefully that way if for example array2[7] does not exists , it wont throw an error because inside $data it would not exist... hope all that makes sense, i can not find a proper way to describe this.
I don't really get what you are doing with with the while "loop" and the array_pop, but for your other problem, you can use a simple foreach:
foreach ($array2 as $arr)
{
$date[] = (isset($arr->DATE)) ? $arr->DATE : '';
}
This will get you an array with all the dates stored at the corresponding key from 0 to x.
i have to update two different tables when submitting a form.
first one is a string containing all hotels information for each posted date
$index = 0;
$insert ="";
foreach($_POST['day'] as $index => $day) {
$day = $day;
$name = $_POST['name'][$index];
$sgl = $_POST['sgl'][$index];
$dbl = $_POST['dbl'][$index];
$nights = $_POST['nights'][$index];
$status = $_POST['status'][$index];
$ref = $_POST['ref'][$index];
$breakfast = $_POST['breakfast'][$index];
$meal = $_POST['meal'][$index];
$insert .= "$day|$name|$sgl|$dbl|$nights|$status|$ref|$breakfast|$meal;";
}
$data['details_accommodation'] = $insert;
This code works ok to update the first table.
i need then to isolate each $day (mysql date) and update a second year table with the same string where $day matches the corresponding date. and i'm stuck. hope i'm clear enough with mu problem !
Instead of Inserting DAY, try to insert UNIX timestamp, in both tables. Hope this resolves your problem
I'd much rather use arrays, and the implode function to join the values, rather than string concatenation. It gives far more flexibility with the values then, and no trailing join value set with the final loop.
My advice: Gather your your data into multiple arrays indexed by "$index", e.g:
$refs[$index] = $value
Then use the implode function to do your concatenation values:
$string = implode(',', $refs);
This will then simplify data arrays for you to manipulate and save. Hope this helps!
I'm using a series of MySQL queries to pull back calculations stored by date for graphing via the Flot library. After the calculations are done, the echoed material looks like this (using UNIX timestamp dates):
Item 1:
[
[1159765200000,-117.875],
[1159851600000,-117.25],
[1159938000000,-120.625],
[1160024400000,-122.125],
[1160110800000,-118.125],
[1160370000000,-121.125],
[1160456400000,-123.375],
[1160542800000,-115.625],
[1160629200000,-117.75],
[1160715600000,-112.75],
[1160974800000,-125.25],
[1161061200000,-135],
[1161147600000,-138.375],
[1161234000000,-137],
[1161320400000,-136.25],
[1161579600000,-139.875],
[1161666000000,-146.625],
[1161752400000,-143.625],
[1161838800000,-150.25],
[1161925200000,-152.875],
[1162188000000,-151.75],
[1162274400000,-149.75]
]
Item 2:
[
[1104732000000,47.3913043478],
[1104818400000,45.5072463768],
[1104904800000,45.5797101449],
[1104991200000,45.115942029],
[1105077600000,44.1739130435],
[1105336800000,44.5362318841],
[1105423200000,45.9565217391],
[1105509600000,45.9420289855],
[1105596000000,46.0289855072],
[1105682400000,46.4347826087],
[1106028000000,48.347826087],
[1106114400000,46.8695652174],
[1106200800000,46.4927536232],
[1106287200000,45.6376811594],
[1106546400000,44.3768115942],
[1106632800000,44.0579710145],
[1106719200000,44.5942028986],
[1106805600000,45.0289855072],
[1106892000000,45.231884058],
[1107151200000,46.1449275362],
[1107237600000,46.5942028986],
[1107324000000,45.5652173913],
[1107410400000,45],
[1107496800000,46.2608695652],
[1107756000000,45.7391304348],
[1107842400000,46.3333333333]
]
Basically I'd like to calculate the average of the second value in each pair, controlling for the date. In other words, for each date that matches in each array, print the date and the average of all the second values in each array, e.g:
[Common Date, Average of all second values]
I've looked through a number of array merging techniques but can't seem to find a workable solution.
Thanks very much for any help.
You could construct an array indexed by date in which you put a list of all values for the date:
$byDate = array();
foreach($item1 as $row) {
$date = sprintf('%.0f', $row[0]);
$byDate[$date][] = $row[1];
}
foreach($item2 as $row) {
$date = sprintf('%.0f', $row[0]);
$byDate[$date][] = $row[1];
}
Then you can easily compute the average for each list:
foreach($byDate as $date => $values) {
$avg = array_sum($values) / count($value);
printf("avg for %s: %f\n", $date, $avg);
}
Or compute all averages at once:
function array_avg($array) {
return array_sum($array) / count($array);
}
$avgByDate = array_map('array_avg', $byDate);
Try it here: http://codepad.org/1S1HrYoB
For your merge
$merged_array = array();
function merge_by_time()
{
$passed_arrays = func_get_args();
$merged_array = array();
foreach($passed_arrays as $array)
foreach($array as $value_set){
$merged_array[$value_set[0]][] = $value_set[1];
}
}
return $merged_array;
}
Usage:
$new_array = merge_by_time($array1, $array2, $array3, ...)
Then you'll have an array based on timestamp that has all associated data values contained in it. I think you can take it from here to get the averages?
Second approach
function merge_by_time_and_get_average()
{
$passed_arrays = func_get_args();
$merged_array = array();
foreach($passed_arrays as $array)
foreach($array as $value_set){
$merged_array[$value_set[0]]['data'][] = $value_set[1];
$merged_array[$value_set[0]]['average'] = 0;
foreach($merged_array[$value_set[0]]['data'] as $data_point){
$merged_array[$value_set[0]]['average'] += $data_point;
}
$merged_array[$value_set[0]]['average'] = $merged_array[$value_set[0]]['average']/count($merged_array[$value_set[0]]['data'])
}
}
return $merged_array;
}
Then you have $array[{timestamp}]['data'] containing your data points and $array[{timestamp}]['average'] containing your average of all data points. The nested foreachs are a little messy and expensive, but you can handle it all in one function call.