Replacing the unusual number in php array - php

I have the array of numbers in php like following
[2021-06-04] => Array
(
[09:15:04] => 1.51
[09:15:27] => 1.32
[09:15:46] => 14.29
[09:16:05] => 14.03
[09:18:05] => 13.97
[09:18:24] => 13.88
[09:18:42] => 13.94
[09:19:01] => 13.80
[09:19:05] => 13.86
[09:19:23] => 13.97
[09:19:41] => 6.99
[09:20:00] => 14.14
[09:20:06] => 14.08
[09:20:25] => 14.04
)
In above array items .. 1.51,1.32 and 6.99 is somewhat off , so i want to replace then with next element so it result array should look like below.
[2021-06-04] => Array
(
[09:15:04] => 14.29
[09:15:27] => 14.29
[09:15:46] => 14.29
[09:16:05] => 14.03
[09:18:05] => 13.97
[09:18:24] => 13.88
[09:18:42] => 13.94
[09:19:01] => 13.80
[09:19:05] => 13.86
[09:19:23] => 13.97
[09:19:41] => 14.14
[09:20:00] => 14.14
[09:20:06] => 14.08
[09:20:25] => 14.04
)
I can get array average using
$a = array_filter($a);
$average = array_sum($a)/count($a);
echo $average;
and I tried something like below
foreach($arr as $key=>$val)
{
if($avg-$val) > 5)
{
$arr[$key] = $nextactualelem; // How do I get next correct element whose $avg-$val is less than 5
}
}
P.s : hi , is it possible to get next 10 elements average.. instead of total average.. because in larger sets its not working fine.. because larger data sets ranging from 10 to 30... so difference of 5 is not working on the initial smaller values.or is there any other faster way to do it like difference between next and previous number..

If you're going to make changes to the array you're working on foreach is not your best choice. referring to keys is troublesome, variable values ale not clean on every run. Generally if you need to do something with the array you're iterating use a for loop instead.
Now since you're going to replace the values, we have a slight issue. Looking at edge cases. What if we want to go over the array in reverse (that makes sense since we want to replace an anomaly with the next value) but the last value is an anomaly? Still reverse order is a good choice but we need to make sure that at least the last value is a valid one.
Given the fact that the keys are rather arbitrary we can't use a for loop at this point. Thankfully we can use the internal array pointer to move around.
$arr = [
'09:15:04' => 1.51,
'09:15:27' => 1.32,
'09:15:46' => 14.29,
'09:16:05' => 14.03,
'09:18:05' => 13.97,
'09:18:24' => 13.88,
'09:18:42' => 13.94,
'09:19:01' => 13.80,
'09:19:05' => 13.86,
'09:19:23' => 13.97,
'09:19:41' => 6.99,
'09:20:00' => 14.14,
'09:20:06' => 14.08,
'09:20:25' => 14.04
];
$average = array_sum($arr)/count($arr);
end($arr); // We move the pointer to the end of the array;
//... do some verification magic here
// so we have a valid starting value on the end of the array
while(prev($arr) != false) { // move one step back while we have values
if (($average - current($arr)) > 5) {
$key = key($arr); // Grab the current key
$arr[$key] = next($arr); // replace the value with the next
prev($arr); // put the pointer back in the right place
}
}
var_dump($arr);
Note that if you run this the 6.99 will remain in the array as it's only 4.71 away from the average. So some tweaks to your conditions might be in order.
EDIT:
taking the new information We could try something along the lines of:
$lookup[] = end($arr); // We move the pointer to the end of the array and place it in a lookup array
//... do some varification magic here so we have a valid starting value on the end of the array
while(prev($arr) !== false) { // move one step back while we have values
$average = array_sum($lookup)/count($lookup); // calculate the current average based on lookup
if (abs($average - current($arr)) > 2) { // if the difference from the current average is more the 2 points
$arr[key($arr)] = next($arr); // replace the value with the next
prev($arr); // put the pointer back in the right place
}
$lookup[] = current($arr); // add the current value to the average
if (count($lookup) > 10) { // if we have more then 10 values in the lookup
array_shift($lookup); // Shift an element off the beginning of array
}
}
This should smooth things out ;)

loop through the reverse of your array, saving the last value, and replace the odd values for the last value that you saved before.
UPDATE:
Now $avg is the average of the next 10 available values.
$arr = [
'09:15:04' => 1.51,
'09:15:27' => 1.32,
'09:15:46' => 14.29,
'09:16:05' => 14.03,
'09:18:05' => 13.97,
'09:18:24' => 13.88,
'09:18:42' => 13.94,
'09:19:01' => 13.80,
'09:19:05' => 13.86,
'09:19:23' => 13.97,
'09:19:41' => 6.99,
'09:20:00' => 14.14,
'09:20:06' => 14.08,
'09:20:25' => 14.04,
];
$avg = 0;
$inverseArr = array_reverse($arr);
$lastValue = false;
$offset = -1;
foreach ($inverseArr as $key => $val) {
if (($avg - $val) > 5 && $lastValue !== false) {
$arr[$key] = $lastValue;
}
else {
$lastValue = $val;
}
$nextTen = array_slice($arr, $offset, 10);
$avg = array_sum($nextTen) / count($nextTen);
$offset--;
}
// array (size=14)
// '09:15:04' => float 14.29
// '09:15:27' => float 14.29
// '09:15:46' => float 14.29
// '09:16:05' => float 14.03
// '09:18:05' => float 13.97
// '09:18:24' => float 13.88
// '09:18:42' => float 13.94
// '09:19:01' => float 13.8
// '09:19:05' => float 13.86
// '09:19:23' => float 13.97
// '09:19:41' => float 14.14
// '09:20:00' => float 14.14
// '09:20:06' => float 14.08
// '09:20:25' => float 14.04

Related

PHP Find median value from array and return key and value?

I have an array of channels, so far I know how to return min and max values like this:
// clear from any empty channels
$channels = array_filter($scan['channels']);
// get min/max values
$min = array_keys($channels, min($channels));
$max = array_keys($channels, max($channels));
// this returns the channel name wich is what I need
So far I would like to get the median key (channel) name, how can I achieve this?
// this is the array of channels
Array
(
[chann_1] => 155.755
[chann_2] => 154.61
[chann_3] => 156.719
[chann_4] => 156.727
[chann_5] => 155.797
[chann_6] => 157.615
[chann_7] => 154.257
[chann_8] => 151.724
[chann_9] => 156.549
[chann_10] => 156.594
[chann_11] => 157.56
[chann_12] => 156.405
)
Try this:.
Sort the array.
Get the array keys.
Then half of count of array_keys is the median value. (I added round just in case).
$arr = Array(
"chann_1" => 155.755,
"chann_2" => 154.61,
"chann_3" => 156.719,
"chann_4" => 156.727,
"chann_5" => 155.797,
"chann_6" => 157.615,
"chann_7" => 154.257,
"chann_8" => 151.724,
"chann_9" => 156.549,
"chann_10" => 156.594,
"chann_11" => 157.56,
"chann_12" => 156.405);
Arsort($arr);
//Var_dump($arr);
$keys = array_keys($arr);
Echo $keys[round(count($keys)/2)];
https://3v4l.org/ER3d4
Usearray_search().$max_key=array_search($max,$yourArray);$min_key=array_search($min,$yourArray);$median=$max_key+$min_key/2;of course it depends on your Array size.
Try $median=array_search($max+$min/2,$yourArra);

Modify Current Value of Multidimensional Array

I have three arrays, say multiarray, valsarray, and otherarray. otherarray is a multidimensional array that supplies values to multiarray and valsarray, but besides that it is unimportant here. valsarray takes values from a subarray of each value in otherarray and multiarray takes straight values from otherarray, as demonstrated below:
foreach($otherarray as $other){
foreach($other as $sub){
$valsarray[] = $sub
}
$multiarray[] = array('Val1' => $other['Val1'], 'Val2' => $other['Val2']);
}
Now what I would like to do is append each key/value pair in valsarray to the current array entry of multiarray, to achieve a result similar to:
$multiarray = array('Val1' => $other['Val1'], 'Val2' => $other['Val2'],
'VALSARRAY_KEY1' => VALSARRAY_VALUE1, ..., 'VALSARRAY_KEYN' => VALSARRAY_VALUEN)
I have attempted to solve this using current in the following fashion:
foreach($valsarray as $key => $val){
current($multiarray)[$key] = $val;
}
But the multiarray remained unaltered. I may be misunderstanding how current works, or how to approach this problem, so any help or direction would be appreciated.
EDIT- EXAMPLE
otherarray = array(...prior array entries...,
array('Val1' => 'abc',
'Val2' => 'cde',
'Val3' => 'not important',
'Val4' => array(0 => 'subA', 1 => 'subB'),
...next array entries...);
BEFORE MERGE:
multiarray = array(...prior entries...,
array('Val1' => 'abc',
'Val2' => 'cde'));
valsarray = array(0 => 'subA', 1 => 'subB');
AFTER MERGE:
multiarray = array(...prior entries...,
array('Val1' => 'abc',
'Val2' => 'cde',
0 => 'subA',
1 => 'subB'));
So if multiarray was a regular array instead of a multidimensional one, I would do something like:
foreach($valsarray as $key => $val){
$multiarray[$key] = $val;
}
To achieve the end result.
I am not 100% sure what you are trying to accomplish a Minimal, Complete, and Verifiable example may help if I have misunderstood something.
It appears that the current() function does not work as you assume. (Or more specifically, the internal pointer.)
If you look at the example in the PHP documentation: Current(), you will see that for current($array) to change elements, you need to call next($array) or prev($array).
These function move the internal pointer of the array.
Note that in PHP 5, foreach loops use the internal pointer (and reset it when you start a loop), but in PHP 7, foreach loops do not use the internal pointer.
Anyway, here is my best guess at what could help you.
$valsarray_index = 0;
foreach ($otherarray as $other) {
$multiarray_value = array('Val1' => $other['Val1'], 'Val2' => $other['Val2']);
foreach ($other as $sub) {
$multiarray_value[$valsarray_index] = $sub;
// $multiarray_value["VALSARRAY_KEY" . $valsarray_index] = $sub;
$valsarray[] = $sub;
$valsarray_index += 1; // This stays in lockstep with the last index of $valsarray
}
$multiarray[] = $multiarray_value;
}
I am not exactly sure about what you want the final output to look like. If this produces incorrect information, then if would be helpful to provide some specific arrays for input and what you expect as output.

Intersection of two multidimensional arrays in PHP

I am having the following array defined:
array(
'name'=>'Blue',
'age'=>'0',
'skin'=>array(
'White Skin','Tanned Skin'
),
'eye'=>array(
'Black','Brown','Honey'
),
'personality'=>array(
'Intelligent','Warm','Trustworthy','Sweet'
),
'ocassion'=>array(
'Every day wear','Celebrations','Restaurant Dinner','Feasts','Visiting friends'
),
'hair'=>'All Colors',
'style'=>array(
'Loved to be admired','Center of attention'
),
'description'=>'Blue lens are perfect for any..'
);
and I am trying to find the number of matches, from an HTML form into this array. A possible return from the HTML form, in array format would be:
Array
(
[age] => 16
[skin] => Tanned Skin
[eye] => Brown
[personality] => Array
(
[0] => Intelligent
[1] => Warm
[2] => Trustworthy
)
[ocassion] => Weddings
[hair] => Dark Brown
[style] => Array
(
[0] => Style Queen
[1] => Testing val
)
)
I have tried iterating trough each key of the first array, but failed to achieve what I want, and also I've tried using the function array_intersect_assoc($stack,$search) but it seems it won't find the exact matches because the $search array ( second example ) has some key=>value pairs that are of type string, and it cannot match any occurrence into the first array because the value is actually an array, and not a string.
Can someone point me an idea or can let me know what's best to do over here?
I have tried a lot of things in the last 3 hours but no success.
Ok, so how about this.
The source data:
$demands = array(
'name'=>'Blue',
'age'=>'0',
'skin'=>array(
'White Skin','Tanned Skin'
),
'eye'=>array(
'Black','Brown','Honey'
),
'personality'=>array(
'Intelligent','Warm','Trustworthy','Sweet'
),
'ocassion'=>array(
'Every day wear','Celebrations','Restaurant Dinner','Feasts','Visiting friends'
),
'hair'=>'All Colors',
'style'=>array(
'Loved to be admired','Center of attention'
),
'description'=>'Blue lens are perfect for any..'
);
$possible_match = array(
'age'=>'16',
'skin'=>'Tanned Skin',
'eye'=>'Brown',
'personality'=>array(
'Intelligent','Warm','Trustworthy'
),
'ocassion'=>array(
'Weddings'
),
'hair'=>'Dark Brown',
'style'=>array(
'Style Queen','Testing value'
)
);
And the match-making algorithm:
$result = array();
$count_matches = 0;
// Go through all the demands
foreach ($demands as $key => $value){
// If there's a matching key in the possible match array
if (isset($possible_match[$key])){
// If there are more demanded values
if (is_array($value)){
// Let all demanded values be lowercase
$value = array_map('strtolower', $value);
// If there are more possible matching values
if (is_array($possible_match[$key])){
// Let all possibly matching values be lowercase, too
$possible_match[$key] = array_map('strtolower', $possible_match[$key]);
// And then do the intersect.
$intersect = array_intersect($value, $possible_match[$key]);
if ($intersect){
// If that intersect is not empty, add that to the resulting array
$result[$key] = $intersect;
$count_matches += count($intersect);
};
} else {
// If there's only one possible matching value, search that
// value in the demaned array
if (in_array(strtolower($possible_match[$key]), $value, true)){
// And add it to the results
$result[$key][] = strtolower($possible_match[$key]);
$count_matches++;
}
}
} else {
if (is_array($possible_match[$key])){
// If there are more possible matching values but the demand is a string,
// find that string in those possible values
$possible_match[$key] = array_map('strtolower', $possible_match[$key]);
if (in_array(strtolower($value), $possible_match[$key], true)){
// And add it to the results
$result[$key] = $value;
$count_matches++;
}
} else {
// If the demanded value is only one (= it's a string and not an array)
// and the possible match is also a string, do a lowercase compare
// + if there's a word "all" in the demanded value, pass it at all times ;D
if (strtolower($possible_match[$key]) == strtolower($value)
|| stripos($value, "all") !== false){
// And add it to the resulting array
$result[$key] = strtolower($value);
$count_matches++;
}
}
}
}
}
var_dump ($result);
var_dump ($count_matches);
There may be some opportunities for optimizing, but the basic idea should be there :)
The result:
array (size=4)
'skin' =>
array (size=1)
0 => string 'tanned skin' (length=11)
'eye' =>
array (size=1)
0 => string 'brown' (length=5)
'personality' =>
array (size=3)
0 => string 'intelligent' (length=11)
1 => string 'warm' (length=4)
2 => string 'trustworthy' (length=11)
'hair' => string 'all colors' (length=10)
Plus the count, if you'd like:
int 6

php multidimensional array get first date value

I need help once again. I have an array and I need to extract earliest day weight value.
EDIT - EDIT - EDIT
array (
3 =>
array (
'id' => '20110211',
'Date' => '2011-02-11',
'Weight' => '195',
),
4 =>
array (
'id' => '20110213',
'Date' => '2011-02-13',
'Weight' => '160',
),
6 =>
array (
'id' => '20110310',
'Date' => '2011-03-10',
'Weight' => '200',
),
12 =>
array (
'id' => '20110301',
'Date' => '2011-03-01',
'Weight' => '55',
),
21 =>
array (
'id' => '20110215',
'Date' => '2011-02-15',
'Weight' => '120',
),
25 =>
array (
'id' => '20110322',
'Date' => '2011-03-22',
'Weight' => '250',
),
)
I've edited this and this code works:
function sortByDate ($arr1, $arr2)
{
return strcmp($arr1['Date'], $arr2['Date']);
}
// $arr is your array
usort($weight_tracker, 'sortByDate');
$earliest = $weight_tracker[0]['Weight'];
echo $earliest;
But since I have a form on this page which updates the array when array is updated - I got message Fatal error: Cannot use string offset as an array in
EDIT -> I've re-declared this as string, hence the ERROR ! be careful when using global and includes as everything can become a mess ! PHP is forgiving, but that "forgiveness" can cost a lot of time later on... :)
Thanks,
Peter
You could sort the array with a custom callback using usort() and then take the first element.
// $arr is your array
usort($arr, 'sortByDate');
$earliest = $arr[0];
function sortByDate ($arr1, $arr2)
{
return strcmp($arr1['Date'], $arr2['Date']);
}
This is one way of doing it:
function filter_min($a, $b) {
return ($a['Date'] < $b['date']) ? $a : $b;
}
$result = array_reduce($array, 'filter_min');
echo $result['Weight'];
Another way is to simply iterate over the array and find the smallest date.
$smallest = null; // array index of entry with smallest weight.
foreach ($array as $idx => $data) {
if (($data['Weight'] < $array[$smallest]['Weight']) || (is_null($smallest))) {
$smallest = $idx; // found a small weight, so save the index
}
}
echo $array[$smallest]['Date'];
I noticed that the dates are in reverse order with the latest date being pulled in first, and the earliest date last. Will it always be like that? If so, you can do this:
$index = count($array) - 1;
$earliestdate = $array[$index]['Date'];
You could also use array_reverse() to invert the array and make the first element the formerly last element.
If this is being pulled in from MySQL you could also alter the query to ORDER BY 'Date' DESC (or is it ASC that would get you what you want, can't remember)

Running calculations on multi-dimensional arrays?

This is probably a real simple question but I'm looking for the most memory efficient way of finding out data on a particular multi-dimensional array.
An example of the array:
[0] => Array(
[fin] => 2
[calc] => 23.34
[pos] => 6665
)
[1] => Array(
[fin] => 1
[calc] => 25.14
[pos] => 4543
)
[2] => Array(
[fin] => 7
[calc] => 21.45
[pos] => 4665
)
I need a method of identifying the values of the following things:
The max 'calc'
The min 'calc'
The max 'pos'
The min 'pos'
(you get the gist)
The only way I can think of is manually looping through each value and adjusting an integer so for example:
function find_lowest_calc($arr) {
$int = null;
foreach($arr['calc'] as $value) {
if($int == null || $int > $value) {
$int = $value;
}
}
return $int;
}
The obvious drawbacks of a method like this is I would have to create a new function for each value in the array (or at least implement a paramater to change the array key) and it will slow up the app by looping through the whole array 3 or more times just to get the values. The original array could have over a hundred values.
I would assume that there would be an internal function to gather all of (for example) the 'calc' values into a temporary single array so I could use the max function on it.
Any ideas?
Dan
$input = array(
array(
'fin' => 2
'calc' => 23.34
'pos' => 6665
),
array(
'fin' => 1
'calc' => 25.14
'pos' => 4543
),
array(
'fin' => 7
'calc' => 21.45
'pos' => 4665
)
);
$output = array(
'fin' => array(),
'calc' => array(),
'pos' => array(),
);
foreach ( $input as $data ) {
$output['fin'][] = $data['fin'];
$output['calc'][] = $data['calc'];
$output['pos'][] = $data['pos'];
}
max($output['fin']); // max fin
max($output['calc']); // max calc
min($output['fin']); // min fin
There is no way to speed that up, besides calculating all three values at once. The reason for this is that you always need to loop through the array to find the sub-arrays. Even if you find a bultin function, the time complexity will be the same. The only way to make a real difference is by using another datastructure (i.e, not any of the bultin ones, but one you write yourself).
How are you receiving the array? If it is your code which is creating the array, you could calculate the minimum and maximum values as you are reading in the data values:
$minCalc = null;
$arr = array();
for(...){
//read in 'calc' value
$subArr = array();
$subArr['calc'] = //...
if ($minCalc === null || $minCalc > $subArr['calc']){
$minCalc = $subArr['calc'];
}
//read in other values
//...
$arr[] = $subArr;
}
Also, in your find_lowest_calc function, you should use the triple equals operator (===) to determine whether the $int variable is null. This is because the statement $int == null will also return true if $int equals 0, because null equals 0 when converted to an integer.
You don't have to crate a new function for each value, just pass the key you want in the function
function find_lowest($arr, $indexkey) {
$int = null;
foreach($arr[$indexkey] as $value) {
if($int == null || $int > $value) {
$int = $value;
}
}
return $int;
}
As php is not type-safe, you should be fine passing both string or int index

Categories