php operands in arrays - php

Hi Guys have the following arrays:
Array
(
[0] => Array
(
[SERIAL] => 1
[SCORE_1] => 6.6490630173025
[SCORE_2] => 13.010510864225
[SCORE_3] => 7.5543177306323
[SCORE_4] => 4.1576775823101
[SCORE_5] => 5.3696604808987
)
[1] => Array
(
[SERIAL] => 2
[SCORE_1] => 11.861835175219
[SCORE_2] => 0
[SCORE_3] => 1.988806017442
[SCORE_4] => 0.97387338276326
[SCORE_5] => 4.0322016758707
)
I need to find the proportion of each element in its array i.e. for example SCORE_1/(SCORE_1+...+SCORE_5) and the serials remain as is. The PHP code looks like this:
$r = -1;
$namedDataArray = array();
for ($row = 2; $row <= $highestRow; ++$row) {
$dataRow = $objWorksheet->rangeToArray('A'.$row.':'.$highestColumn.$row,null, true, true, true);
if ((isset($dataRow[$row]['A'])) && ($dataRow[$row]['A'] > '')) {
++$r;
foreach($headingsArray as $columnKey => $columnHeading) {
if($dataRow[$row][$columnKey]==0){
$namedDataArray[$r][$columnHeading] = 0;
}elseif($columnHeading=='SERIAL' ){
$namedDataArray[$r][$columnHeading]=$dataRow[$row][$columnKey];
} else {
$x=(float)1.35;
$a=pow($dataRow[$row][$columnKey],$x);
$namedDataArray[$r][$columnHeading] = $a;
}
}
}
}
echo '<pre>';
print_r($namedDataArray);
echo '</pre><hr />';
I'm still new to php and have been struggling with this one. I used PHPExcel to read the file and raise each element to the power of 1.35 . I've used $total=array_sum($namedDataArray) but when I try to divide i.e$Score= $namedDataArray/$total it says unsupported operand type.

On this line :
$Score= $namedDataArray/$total
$namedDataArray is an array. PHP doesn't allow you to perform a division with an array, you have to put a number instead, for i.e. $Score = $namedDataArray[0]['SCORE_1'] / $total

Related

PHP - add values to already existing array

I have a already defined array, containing values just like the one below:
$arr = ['a','b','c'];
How could one add the following using PHP?
$arr = [
'a' => 10,
'b' => 5,
'c' => 21
]
I have tried:
$arr['a'] = 10 but it throws the error: Undefined index: a
I am surely that I do a stupid mistake.. could someone open my eyes?
Full code below:
$finishes = []; //define array to hold finish types
foreach ($projectstages as $stage) {
if ($stage->finish_type) {
if(!in_array($stage->finish_type, $finishes)){
array_push($finishes, $stage->finish_type);
}
}
}
foreach ($projectunits as $unit) {
$data[$i] = [
'id' => $unit->id,
'project_name' => $unit->project_name,
'block_title' => $unit->block_title,
'unit' => $unit->unit,
'core' => $unit->core,
'floor' => $unit->floor,
'unit_type' => $unit->unit_type,
'tenure_type' => $unit->tenure_type,
'floors' => $unit->unit_floors,
'weelchair' => $unit->weelchair,
'dual_aspect' => $unit->dual_aspect
];
$st = array();
$bs = '';
foreach ($projectstages as $stage) {
$projectmeasure = ProjectMeasure::select('measure')
->where('project_id',$this->projectId)
->where('build_stage_id', $stage->id)
->where('unit_id', $unit->id)
->where('block_id', $unit->block_id)
->where('build_stage_type_id', $stage->build_stage_type_id)
->first();
$st += [
'BST-'.$stage->build_stage_type_id => ($projectmeasure ? $projectmeasure->measure : '0')
];
if (($stage->is_square_meter == 0) && ($stage->is_draft == 0)) {
$height = ($stage->height_override == 0 ? $unit->gross_floor_height : $stage->height_override); //08.14.20: override default height if build stage type has it's own custom height
$st += [
'BST-sqm-'.$stage->build_stage_type_id => ($projectmeasure ? $projectmeasure->measure * $height: '0')
];
if ($stage->finish_type) {
$finishes[$stage->finish_type] += ($projectmeasure ? $projectmeasure->measure * $height: '0') * ($stage->both_side ? 2 : 1); //error is thrown at this line
}
} else {
if ($stage->finish_type) {
$finishes[$stage->finish_type] += ($projectmeasure ? $projectmeasure->measure : '0');
}
}
}
$data[$i] = array_merge($data[$i], $st);
$data[$i] = array_merge($data[$i], $finishes[$stage->finish_type]);
$i++;
}
The above code is used as is and the array $finishes is the one from the first example, called $arr
You're using += in your real code instead of =. That tries to do maths to add to an existing value, whereas = can just assign a new index with that value if it doesn't exist.
+= can't do maths to add a number to nothing. You need to check first if the index exists yet. If it doesn't exist, then assign it with an initial value. If it already exists with a value, then you can add the new value to the existing value.
If you want to convert the array of strings to a collection of keys (elements) and values (integers), you can try the following:
$arr = ['a','b','c'];
$newVals = [10, 5, 21];
function convertArr($arr, $newVals){
if(count($arr) == count($newVals)){
$len = count($arr);
for($i = 0; $i < $len; $i++){
$temp = $arr[$i];
$arr[$temp] = $newVals[$i];
unset($arr[$i]);
}
}
return $arr;
}
print_r(convertArr($arr, $newVals));
Output:
Array ( [a] => 10 [b] => 5 [c] => 21 )

How to use array values as keys without loops? [duplicate]

This question already has answers here:
Generate an associative array from an array of rows using one column as keys and another column as values
(3 answers)
Closed 7 months ago.
Looping is time consuming, we all know that. That's exactly something I'm trying to avoid, even though it's on a small scale. Every bit helps. Well, if it's unset of course :)
On to the issue
I've got an array:
array(3) {
'0' => array(2) {
'id' => 1234,
'name' => 'blablabla',
},
'1' => array(2) {
'id' => 1235,
'name' => 'ababkjkj',
},
'2' => array(2) {
'id' => 1236,
'name' => 'xyzxyzxyz',
},
}
What I'm trying to do is to convert this array as follows:
array(3) {
'1234' => 'blablabla',
'1235' => 'asdkjrker',
'1236' => 'xyzxyzxyz',
}
I guess this aint a hard thing to do but my mind is busted right now and I can't think of anything except for looping to get this done.
Simply use array_combine along with the array_column as
array_combine(array_column($array,'id'), array_column($array,'name'));
Or you can simply use array_walk if you have PHP < 5.5 as
$result = array();
array_walk($array, function($v)use(&$result) {
$result[$v['id']] = $v['name'];
});
Edited:
For future user who has PHP > 5.5 can simply use array_column as
array_column($array,'name','id');
Fiddle(array_walk)
UPD: Warning the slowest solution! See benchmarks below.
Try this code:
$a = array(array('id' => 1234,
'name' => 'blablabla'),
array('id' => 1235,
'name' => 'ababkjkj'),
array('id' => 1236,
'name' => 'xyzxyzxyz'));
var_export(array_reduce($a, function($res, $item) {
$res[$item['id']] = $item['name'];
return $res;
}));
Works fine even in PHP 5.3. And uses only one function array_reduce.
UPD:
Here are some benchmarks (PHP 5.6 over Debian 7 on a medium quality server):
$a = [];
for ($i = 0; $i < 150000; $i++) {
$a[$i] = ['id' => $i,
'name' => str_shuffle('abcde') . str_shuffle('01234')];
}
$start = microtime(true);
if (false) {
// 7.7489550113678 secs for 15 000 itmes
$r = array_reduce($a, function($res, $item) {
$res[$item['id']] = $item['name'];
return $res;
});
}
if (false) {
// 0.096649885177612 secs for 150 000 items
$r = array_combine(array_column($a, 'id'),
array_column($a, 'name'));
}
if (true) {
// 0.066264867782593 secs for 150 000 items
$r = [];
foreach ($a as $subarray) {
$r[$subarray['id']] = $subarray['name'];
}
}
if (false) {
// 0.32427287101746 secs for 150 000 items
$r = [];
array_walk($a, function($v) use (&$r) {
$r[$v['id']] = $v['name'];
});
}
echo (microtime(true) - $start) . ' secs' . PHP_EOL;
So, as a conclusion: plain iteration with simple for loop is a winner (as mentioned in this answer). On a second place there is array_combine allowed only for new versions of PHP. And the worst case is using my own solution with closure and array_reduce.
If you have php >= 5.5:
$res = array_combine(array_column($source, 'id'), array_column($source, 'name'));
If not - make a loop.
Make use of array_map function, (PHP 4 >= 4.0.6, PHP 5)
[akshay#localhost tmp]$ cat test.php
<?php
$array = array(
array('id' => 1234,'name' => 'blablabla'),
array('id' => 1235,'name' => 'ababkjkj'),
array('id' => 1236,'name' => 'xyzxyzxyz')
);
$output = array();
array_map(function($_) use (&$output){ $output[$_['id']] = $_['name']; },$array);
// Input
print_r($array);
// Output
print_r($output);
?>
Output
[akshay#localhost tmp]$ php test.php
Array
(
[0] => Array
(
[id] => 1234
[name] => blablabla
)
[1] => Array
(
[id] => 1235
[name] => ababkjkj
)
[2] => Array
(
[id] => 1236
[name] => xyzxyzxyz
)
)
Array
(
[1234] => blablabla
[1235] => ababkjkj
[1236] => xyzxyzxyz
)
This is the fastest and simplest code here so far ...
$result = [];
foreach ($input as $subarray) {
$result[$subarray["id"]] = $subarray["name"];
}
Try this function:
array_combine(array_column($array,'id'), array_column($array,'name'));

Compare two arrays and append last values if they are the same else value zero

I have two string values namely $late_array and $wrong_array. The values are comma delimited.
What I would like to do is compare the two arrays and if the first two elements are the same add the value to the end else make it zero. The arrays I have:
$late_array = array(
[0] => 140610d,Richard,12
[1] => 140610a,Dave,22
[2] => 140610n,Noddy,121
[3] => 140610a,Nick,15
)
$wrong_array = array(
[0] => 140610d,Richard,2
[1] => 140610d,Mary,60
[2] => 140610a,Dave,11
[3] => 140610n,Noddy,90
)
The end result should be:
$combined_array = array(
[0] => 140610d,Richard,12,2
[1] => 140610d,Mary,0,60
[2] => 140610a,Dave,22,11
[3] => 140610a,Nick,15,0
[4] => 140610n,Noddy,121,90
)
I have so far formed a foreach and used the '===' operators to check if the date and name match then output as I want but I have not been able to get it to work if the name is not present in one array but another to make the value zero.
EDIT: Just to clear it up, hopefully. If the value is present in both arrays then the date,name,late value,wrong value should show. But if the value is present in late only then the value for wrong should be 0, same visa versa. Added "Nick" to try and explain a bit better.
This is what I did to solve the problem so far:
$wrong_val = array();
foreach($out as $wrong_value) {
$wrong_tosearch[] = substr($wrong_value,0,strrpos($wrong_value,","));
$w_id = substr($wrong_value,0,strrpos($wrong_value,","));
$wrong_val[$w_id] = substr($wrong_value,strrpos($wrong_value,",")+1,strlen($wrong_value));
}
foreach($sql_late_array as $late_value) {
$late_tosearch[] = substr($late_value,0,strrpos($late_value,","));
$l_id = substr($late_value,0,strrpos($late_value,","));
$late_val[$l_id] = substr($late_value,strrpos($late_value,",")+1,strlen($late_value));
}
$merge = array_merge($wrong_tosearch,$late_tosearch);
$sort = array_values(array_unique($merge));
$combined_array = array();
foreach ($sort as $search_val) {
if (array_key_exists($search_val,$wrong_val) !== FALSE) {
foreach ($wrong_val as $w_key=>$w_val) {
$combined_array[$w_key]['late'] = "0";
$combined_array[$w_key]['wrong'] = $w_val;
}
}
if (array_key_exists($search_val,$late_val) !== FALSE) {
foreach ($late_val as $l_key=>$l_val) {
$combined_array[$l_key]['wrong'] = "0";
$combined_array[$l_key]['late'] = $l_val;
}
}
}
print_r($combined_array);
Check if below code solves your problem.
$late_array = array(
"0" => "140610d,Richard,12",
"1" => "140610a,Dave,22",
"2" => "140610n,Noddy,121"
);
$wrong_array = array(
"0" => "140610d,Richard,2",
"1" => "140610d,Mary,60",
"2" => "140610a,Dave,11",
"3" => "140610n,Noddy,90"
);
foreach($wrong_array as $wv)
{
$tosearch = substr($wv,0,strrpos($wv,",")-1);
$valtoadd = substr($wv,strrpos($wv,",")+1,strlen($wv));
$added=false;
foreach($late_array as $lv)
{
if(strstr($lv, $tosearch) !== false)
{
$combined_array[] = $lv.",".$valtoadd;
$added=true;
break;
}
}
if(!$added)
$combined_array[] = $tosearch.",0,".$valtoadd;
}
$tcombined_array = $combined_array;
foreach($late_array as $wv)
{
$added = false;
foreach($tcombined_array as $cv)
if(strstr($cv,$wv))
$added = true;
if(!$added) $combined_array[] = $wv.",0";
}
print_r($combined_array);
May be big but works
<?php
$late_array = array(
0 => "140610d,Richard,12",
1 => "140610a,Dave,22",
2 => "140610n,Noddy,121",
);
$wrong_array = array(
0 => "140610d,Richard,2",
1 => "140610d,Mary,60",
2 => "140610a,Dave,11",
3 => "140610n,Noddy,90"
);
$pattern = "/[0-9]*[a-zA-Z]*,[0-9]*[a-zA-Z]*,/";
$combined_array = $late_array;
foreach($wrong_array as $wrong_index => $wrong_value){
foreach($late_array as $late_index => $late_value){
preg_match_all($pattern, $late_value, $late_matches);
preg_match_all($pattern, $wrong_value, $wrong_matches);
if($late_matches[0] == $wrong_matches[0]){
$explode = explode(',',$wrong_value);
$combined_array[$late_index] = $combined_array[$late_index].','.$explode[2];
$matchedValues[] = $wrong_index;
}
}
}
$unmatched_values = array_diff(array_keys($wrong_array), array_values($matchedValues));
foreach($unmatched_values as $key => $value){
$combined_array[] = $wrong_array[$value].',0';
}
echo '<pre>';
print_r($combined_array);
?>

PHP unpack array

I would like to learn a smart way to unpack nested array. For instance, i have an array variable $rma_data['status'] which looks like below;
[status] => Array
(
[0] => Array
(
[created] => 1233062304107
[statusId] => 5
[statusName] => Open
)
[1] => Array
(
[created] => 1233061910603
[statusId] => 2
[statusName] => New
)
[2] => Array
(
[created] => 1233061910603
[statusId] => 1
[statusName] => Created
)
)
I would like to store the Created timestamps and statusId into an variables based on the condition like: if we find out there is "Open" status exist, we will use Open instead of "New" and "Created" . If there is only New and Created, we will use New instead .
Current version of my way to do that:
for($i=0; $i<count($rma_data['status']); $i++)
{
switch($rma_data['status'][$i]['statusId'])
{
case 5:
case 2:
case 3:
}
Any ideas?
For small to medium scale, what you already have looks good.
My only suggestions would be to use additional variables, for example the count and to unroll some of the compact code to be more efficient and readable.
For example:
$total=count($rma_data['status']);
for($i=0; $i<$total; $i++){
$x=$rma_data['status'][$i];
if($x['statusName']=='Open'){ // Use your criteria
$t=$x['created'];
//...Do Work
}
}
If you're really depended on these three specific values of statusName, a more straightforward and readable way to go about it would be to create an indexed array of status types which you can test more easily.
For example:
$rma_statuses = array();
foreach ((array)$rma_data['status'] as $status) :
$rma_statuses[$status['statusName']] = array(
'created'=>$status['created'],
'id'=>$status['statusId']
);
endforeach;
$rma_stauts = $rma_statuses['open'] ?: ($rma_statuses['new'] ?: $rma_statuses['created']);
// Do something with $rma_stauts['created'] and $rma_stauts['id']
I do not quite understand a necessary condition but it can be like this will help:
$searched_status_id = null;
$searched_timestamp = null;
foreach ($rma_data['status'] as $id => $status) {
if ((!$searched_timestamp && !$searchуd_status_id) ||
($status['statusName'] == 'New' || $status['statusName'] == 'Open')) {
$searched_timestamp = $status['created'];
$searched_status_id = $status['statusId'];
}
if ($status['statusName'] == 'Open') {
break;
}
}
if(is_array($rma_data['status'])){
//assuming there are only three values inside it
//case1
$open = ( $rma_data['status'][0]['statusName'] == 'Open' ||
$rma_data['status'][1]['statusName'] == 'Open' ||
$rma_data['status'][2]['statusName'] == 'Open');
//case2
$new = (!$open &&
($rma_data['status'][0]['statusName'] == 'New' ||
$rma_data['status'][1]['statusName'] == 'New' ||
$rma_data['status'][2]['statusName'] == 'New' ));
if($open){
echo 'open';
}elseif($new){
echo 'New';
}else{
echo 'None';
}
}
Second:
foreach($rma_data['status'] as $key => $val){
$statusName = $val['statusName'];
$newarray[$statusName] = $val;
}
echo '<pre>';
print_r($newarray);
if(array_key_exists('Open', $newarray)){
$created = $newarray['Open']['created'];
$statusId = $newarray['Open']['statusId'];
echo 'Open';
}
elseif(array_key_exists('New', $newarray)){
$created = $newarray['New']['created'];
$statusId = $newarray['New']['statusId'];
echo 'New';
}else{
echo "None";
}

Pad short input arrays with their last element value to ensure equal lengths and transpose arrays into one array

I have the following Arrays:
$front = array("front_first","front_second");
$inside = array("inside_first", "inside_second", "inside_third");
$back = array("back_first", "back_second", "back_third","back_fourth");
what I need to do is combine it so that an output would look like this for the above situation. The output order is always to put them in order back, front, inside:
$final = array(
"back_first",
"front_first",
"inside_first",
"back_second",
"front_second",
"inside_second",
"back_third",
"front_second",
"inside_third",
"back_fourth",
"front_second",
"inside_third"
);
So basically it looks at the three arrays, and whichever array has less values it will reuse the last value multiple times until it loops through the remaining keys in the longer arrays.
Is there a way to do this?
$front = array("front_first","front_second");
$inside = array("inside_first", "inside_second", "inside_third");
$back = array("back_first", "back_second", "back_third","back_fourth");
function foo() {
$args = func_get_args();
$max = max(array_map('sizeof', $args)); // credits to hakre ;)
$result = array();
for ($i = 0; $i < $max; $i += 1) {
foreach ($args as $arg) {
$result[] = isset($arg[$i]) ? $arg[$i] : end($arg);
}
}
return $result;
}
$final = foo($back, $front, $inside);
print_r($final);
demo: http://codepad.viper-7.com/RFmGYW
Demo
http://codepad.viper-7.com/xpwGha
PHP
$front = array("front_first", "front_second");
$inside = array("inside_first", "inside_second", "inside_third");
$back = array("back_first", "back_second", "back_third", "back_fourth");
$combined = array_map("callback", $back, $front, $inside);
$lastf = "";
$lasti = "";
$lastb = "";
function callback($arrb, $arrf, $arri) {
global $lastf, $lasti, $lastb;
$lastf = isset($arrf) ? $arrf : $lastf;
$lasti = isset($arri) ? $arri : $lasti;
$lastb = isset($arrb) ? $arrb : $lastb;
return array($lastb, $lastf, $lasti);
}
$final = array();
foreach ($combined as $k => $v) {
$final = array_merge($final, $v);
}
print_r($final);
Output
Array
(
[0] => back_first
[1] => front_first
[2] => inside_first
[3] => back_second
[4] => front_second
[5] => inside_second
[6] => back_third
[7] => front_second
[8] => inside_third
[9] => back_fourth
[10] => front_second
[11] => inside_third
)
Spreading the column data from multiple arrays with array_map() is an easy/convenient way to tranpose data. It will pass a full array of elements from the input arrays and maintain value position by assigning null values where elements were missing.
Within the custom callback, declare a static cache of the previously transposed row. Iterate the new transposed row of data and replace any null values with the previous rows respective element.
After transposing the data, call array_merge(...$the_transposed_data) to flatten the results.
Code: (Demo)
$front = ["front_first", "front_second"];
$inside = ["inside_first", "inside_second", "inside_third"];
$back = ["back_first", "back_second", "back_third", "back_fourth"];
var_export(
array_merge(
...array_map(
function(...$cols) {
static $lastSet;
foreach ($cols as $i => &$v) {
$v ??= $lastSet[$i];
}
$lastSet = $cols;
return $cols;
},
$back,
$front,
$inside
)
)
);
Output:
array (
0 => 'back_first',
1 => 'front_first',
2 => 'inside_first',
3 => 'back_second',
4 => 'front_second',
5 => 'inside_second',
6 => 'back_third',
7 => 'front_second',
8 => 'inside_third',
9 => 'back_fourth',
10 => 'front_second',
11 => 'inside_third',
)

Categories