Update value of key in array - php

I want to multiply the value of all 'imdb' keys by 10 and update the value. In the code below when I print_r $horrorMovies it just shows I have created a new array with the required amounts. Its almost there if i do
$horrorMovies[0]['imdb'] = $imdbPercent;
But the values just get written to the first nested array.
Im not sure how to make this work with foreach, if it is possible.
function imdbMultiply($n) {
return($n['imdb'] * 10);
}
$horrorMovies = array(
array(
"title" => "The babadook",
"imdb" => 6.8,
"rotten" => 98
),
array(
"title" => "The shining",
"imdb" => 8.4,
"rotten" => 87
)
);
$imdbPercent = array_map("imdbMultiply", $horrorMovies);
$horrorMovies['imdb'] = $imdbPercent;

There's a few problems with your code:
Your imdbMultiply function needs to return the $n array, but modified so the imdb key is multiplied by 10.
array_map returns the new array, so you should set $horrorMovies to the result of array_map
In the end, your code should look like this:
function imdbMultiply ($n) {
$n['imdb'] *= 10;
return $n;
}
$horrorMovies = array_map('imdbMultiply', $horrorMovies);

//original data
$horrorMovies = array(
array(
"title" => "The babadook",
"imdb" => 6.8,
"rotten" => 98
),
array(
"title" => "The shining",
"imdb" => 8.4,
"rotten" => 87
)
);
//define "transformation" function, note that the argument is passed via reference
function imdbMultiply(&$n) {
$n['imdb'] *= 10;
}
//one option is to use foreach and then unset the reference to the
//last array element
foreach($horrorMovies as &$v){
$v['imdb'] *= 10;
}
unset($v);
print_r($horrorMovies);
//alternatively, one might apply the "transformation" function
//directly to each array element without the need to create a copy
array_walk($horrorMovies, "imdbMultiply");
print_r($horrorMovies);

You can just foreach the subarray[imdb] items.
$horrorMovies = array(
array(
"title" => "The babadook",
"imdb" => 6.8,
"rotten" => 98
),
array(
"title" => "The shining",
"imdb" => 8.4,
"rotten" => 87
)
);
foreach($horrorMovies as &$subarray){
$subarray["imdb"] *= 10;
}
var_dump($horrorMovies);
https://3v4l.org/ub40E

You just need to go into a loop and change the 'imdb' values, add the next
for loop to your code:
for ($i=0; $i<count($horrorMovies); $i++){
$horrorMovies[$i]['imdb']*=10;
}

If I understand what you expect, your imdbMultiply() function should be the following to be used with array_map :
function imdbMultiply($n) {
$n['imdb'] *= 10;
return $n;
}
Is it what you expect ?
Another idea is to use array_walk function, but you should define your imdbMultiply() function like this :
function imdbMultiply(&$n) {
$n['imdb'] *= 10;
}
The usage of array_walk is different :
array_walk($horrorMovies, "imdbMultiply");
var_dump($horrorMovies);

Related

PHP adding values inside multidimensional array

Please find below the code sample for adding repeated values inside inner array. Can anyone suggest an alternative way to add the values faster? The code will work with smaller arrays, but I want to add big arrays that contain huge amount of data. Also I want to increase execution time.
<?php
$testArry = array();
$testArry[0] = array(
"text" => "AB",
"count" => 2
);
$testArry[1] = array(
"text" => "AB",
"count" => 5
);
$testArry[2] = array(
"text" => "BC",
"count" => 1
);
$testArry[3] = array(
"text" => "BD",
"count" => 1
);
$testArry[4] = array(
"text" => "BC",
"count" => 7
);
$testArry[5] = array(
"text" => "AB",
"count" => 6
);
$testArry[6] = array(
"text" => "AB",
"count" => 2
);
$testArry[7] = array(
"text" => "BD",
"count" => 111
);
$match_key = array();
$final = array();
foreach ($testArry as $current_key => $current_array) {
$match_key = array();
foreach ($testArry as $search_key => $search_array) {
$key = '';
if ($search_array['text'] == $current_array['text']) {
$match_key[] = $search_key;
$key = $search_array['text'];
if (isset($final[$key])) {
$final[$key] += $search_array['count'];
} else {
$final[$key] = $search_array['count'];
}
}
}
for ($j = 0; $j < count($match_key); $j++) {
unset($testArry[$match_key[$j]]);
}
}
print_r($final);
?>
Anyway to add memory during the execution time?
Thank you.
One array_walk will be enough to solve your problem,
$final = [];
array_walk($testArry, function($item) use(&$final){
$final[$item['text']] = (!empty($final[$item['text']]) ? $final[$item['text']] : 0) + $item['count'];
});
print_r($final);
Output
Array
(
[AB] => 15
[BC] => 8
[BD] => 112
)
Demo
array_walk — Apply a user supplied function to every member of an array
array_map() - Applies the callback to the elements of the given arrays
array_key_exists() - Checks if the given key or index exists in the array
You can use array_walk and array_key_exists to iterate through the array element and sum the one which has text index same
$res = [];
array_map(function($v) use (&$res){
array_key_exists($v['text'], $res) ? ($res[$v['text']] += $v['count']) : ($res[$v['text']] = $v['count']);
}, $testArry);

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'));

PHP find array key in two dimension array

<?php
$x = array(
"C_Card_ID" => array(
"dbName"=>"CardID",
"type"=>"disabled",
"key"=>"primary"
),
"C_Payroll_ID" => array(
"dbName"=> "PayrollID",
"key"=>"unique"
),
"C_First_Name" => array("dbName"=>"FirstName")
?>
I want keys of $x which has "key" index in its second array. In simple words, i need C_Card_ID and C_Payroll_ID as an output in array, so later i will implode them.
Required output Sample : Array("C_Card_ID","C_Payroll_ID")
Please don't use Loop algo. I need to use some build-in function.
You can use array_filter:
syntax is:
$filtered_array = array_keys(array_filter($x, function($a){ return isset($a['key']); }));
This should do:
$result = array_keys(array_filter($x, function($arr){
return array_key_exists('key', $arr);
}));
Try to use array_slice() like,
<?php
$x = array(
"C_Card_ID" => array(
"dbName"=>"CardID",
"type"=>"disabled","key"=>"primary"
),
"C_Payroll_ID" => array(
"dbName"=> "PayrollID",
"key"=>"unique"
),
"C_First_Name" => array("dbName"=>"FirstName"));
print_r(array_slice(array_keys($x),0,2));
//Outputs
//Array ( [0] => C_Card_ID [1] => C_Payroll_ID )
?>
Tested on http://writecodeonline.com/php/

PHP-Sort array based on another array?

OK, I already got this question in stackoverflow but sadly it's in javascript - Javascript - sort array based on another array
and I want it in PHP
$data = array(
"item1"=>"1",
"item2"=>"3",
"item3"=>"5",
"item4"=>"2",
"item5"=>"4"
);
to match the arrangement of this array:
sortingArr = array("5","4","3","2","1");
and the output I'm looking for:
$data = array(
"item3"=>"5",
"item5"=>"4",
"item2"=>"3",
"item4"=>"2",
"item1"=>"1"
);
Any idea how this can be done?
Thanks.
For a detailed answer, why array_multisort does not match your needs, view this answer, please:
PHP array_multisort not sorting my multidimensional array as expected
In short: You want to sort an array based on a predefined order. The Answer is also given over there, but i copied one solution to this answer, too:
Use usort and array_flip, so you be able to turn your indexing array (ValueByPosition) into a PositionByValue Array.
$data = array(
"item1"=>"1",
"item2"=>"3",
"item3"=>"5",
"item4"=>"2",
"item5"=>"4"
);
usort($data, "sortByPredefinedOrder");
function sortByPredefinedOrder($leftItem, $rightItem){
$order = array("5","4","3","2","1");
$flipped = array_flip($order);
$leftPos = $flipped[$leftItem];
$rightPos = $flipped[$rightItem];
return $leftPos >= $rightPos;
}
print_r($data);
// usort: Array ( [0] => 5 [1] => 4 [2] => 3 [3] => 2 [4] => 1 )
// uasort: Array ( [item3] => 5 [item5] => 4 [item2] => 3 [item4] => 2 [item1] => 1 )
However this would require you to predict all possible items inside the predefined order array, or thread other items in an appropriate way.
If you want to maintain the assoc keys, use uasort instead of usort.
Pretty simple ?
$data = array(
"item1"=>"1",
"item2"=>"3",
"item3"=>"5",
"item4"=>"2",
"item5"=>"4"
);
$sortingArr = array("5","4","3","2","1");
$result = array(); // result array
foreach($sortingArr as $val){ // loop
$result[array_search($val, $data)] = $val; // adding values
}
print_r($result); // print results
Output:
Array
(
[item3] => 5
[item5] => 4
[item2] => 3
[item4] => 2
[item1] => 1
)
using usort() the right way i think
Sort an array by values using a user-defined comparison function
you can do as follow:
$data = array(
"item1"=>"1",
"item2"=>"3",
"item3"=>"5",
"item4"=>"2",
"item5"=>"4"
);
$sortingArr = array("5","4","3","2","1");
$keys = array_flip($sortingArr);
usort($data, function ($a, $b) use ($keys) {
return $keys[$a] > $keys[$b] ? 1 : -1;
});
print_r($data);
// Output
// Array ( [0] => 5 [1] => 4 [2] => 3 [3] => 2 [4] => 1 )
live example: https://3v4l.org/75cnu
Look at my following snippet to sort your array based on another array:
$res_arr = array();
for ($i = 0; $i < count($sortingArr); $i++) {
for ($j = 0; $j < count($data); $j++) {
if($data[$j] == $sortingArr[$i]) {
$res_arr[] = $data[$j];
break;
}
}
}
// $res_array is your sorted array now
Look at code snippet to make a multidimensional array sort in order of input
$input_format_list = [4, 1];
$data = array(
"0" => array(
"School" => array(
"id" => 1,
"name" => "ST.ANN'S HIGH SCHOOL",
)
),
"1" => array(
"School" => array(
"id" => 4,
"name" => "JYOTI VIDHYA VIHAR",
)
)
);
$result = array(); // result array
foreach($input_format_list as $key => $value){ // loop
foreach ($data as $k => $val) {
if ($data[$k]['School']['id'] === $value) {
$result[$key] = $data[$k];
}
}
}
return $result;
Take a look at array_multisort. I'm not completely sure how to use it, as I have never found a practical use for it (I prefer to use usort to clearly define my terms), but it might work for you.
<?php
$data = array(
"item1"=>"1",
"item2"=>"3",
"item3"=>"5",
"item4"=>"2",
"item5"=>"4"
);
$result=array_flip($data);
krsort($result);
$result=array_flip($result);
print_r($result);
//use rsort for the index array
$sortingArr = array("5","4","3","2","1");
print_r($sortingArr);
I'm pretty proud of my solution:
uasort($data, function($a, $b) use ($sortingArr) {
return array_search($a, $sortingArr) <=> array_search($b, $sortingArr);
});
Working example: https://3v4l.org/bbIk2
It uses uasort to maintain the key-value associations as the OP requested. (unlike #hassan's otherwise elegant solution)
It doesn't require that every element in the $data array be present in the sorting array. (like #HamZa's solution)
It's brief.
It uses the spaceship operator <=> for comparison instead of more verbose logic.
Code:
Expanding on the Answer of Andrew, if you want the undefined entries in the sorting array to appear at the end of the output array:
uasort($currentTags, function ($a, $b) use ($sortingArr) {
if (in_array($a, $sortingArr) && !in_array($b, $sortingArr)) return -1;
if (!in_array($a, $sortingArr) && in_array($b, $sortingArr)) return 1;
if (!in_array($b, $sortingArr)) return -1;
return array_search($a, $sortingArr) <=> array_search($b, $sortingArr);
});

returning the min array value index

I Am trying to compare 3 different array prices in order to find the lowest so that I can decide which array values should be input into a database, the code looks something like this at the moment...
$array_a = array(
"id" => 398,
"price" => 100
);
$array_b = array(
"id" => 387,
"price" => 60
);
$array_c = array(
"id" => 127,
"price" => 50
);
if($array_a && $array_b && $array_c){
$newArr = array($array_a['price'], $array_b['price'], $array_c['price']);
array_keys($newArr, min($newArr));
print_r($newArr)."\n";
}
The above code does not return the correct index of the array with the lowest price which in this case would be 2 (array_c), what would be the correct way to find out the key of the lowest value.
Also what would be the best way to make sure that only numbers are compared with the min() function as opposed to strings?
You can automate it for example in this manner:
$newArr = array($array_a['price'], $array_b['price'], $array_c['price']);
asort($newArr, SORT_NUMERIC);
echo "Minimum: ".reset($newArr).", given in array #".key($newArr);
I 'm not so sure how to answer your closing question -- what should happen if the values are not actually typed as numbers?
Update: Here's one way to exclude non-numeric values:
asort($newArr, SORT_NUMERIC);
while (!is_numeric(current($newArr))) next($newArr);
if (key($newArr) === null) {
echo "No valid elements found";
}
else {
echo "Minimum: ".current($newArr).", given in array #".key($newArr);
}
You can do:
$newArr = array($array_a['price'], $array_b['price'], $array_c['price']);
sort($newArr);
$lowest = array_shift($newArr);
Try this:
$keys = array_keys($your_array);
asort($keys);
$min = $keys[0];
echo "Smallest index: ".$min;
<?php
$array_a = array(
"id" => 398,
"price" => 100
);
$array_b = array(
"id" => 387,
"price" => 60
);
$array_c = array(
"id" => 127,
"price" => 50
);
if($array_a && $array_b && $array_c){
$newArr = array($array_a['price'], $array_b['price'], $array_c['price']);
$key_min = array_keys($newArr, min($newArr));
echo $key_min[0];
}
?>

Categories