php; Adding to the value of a multidimensional array in a loop - php

So I'm trying to make an array for stat growths in a fake rpg. It looks like this.
// base array
// $base: starting base stats
// $growth: growth rate per rng
$growths = array(
'HP' => array (70 => 20),
'STR' => array (50 => 7),
'MAG' => array (35 => 2),
'SKL' => array (45 => 6),
'SPD' => array (50 => 8),
'LCK' => array (55 => 5),
'DEF' => array (45 => 6),
'RES' => array (15 => 4),
);
//rng calculator
for ($x = 0; $x <= 20; $x++) {
foreach ($growths as $stat_name => $info) {
$roll = rand(0,100);
foreach ($info as $growth => $base) {
if ($roll <= $growth) {
$info[$growth] = ++$base;
print "(UP!) ";
}
echo "$stat_name: $base<br/ >";
}
}
}
My only issue is that the new $base value after the rng calculator refuses to store in the original array. Am I doing something wrong, or do I just need to rebuild the array from scratch and try something else? Any help would be appreciated!

In your first foreach loop, you assign the key of $growths to $stat_name and the value to $info. These are temporary variables. If you change them, the original array is not affected.
// This won't work because $info is temporary.
$info[$growth] = ++$base;
Instead, simply refer to the original array:
// Do this instead.
$growths[$stat_name][$growth] = ++$base;

use reference
just use foreach ($growths as $stat_name => &$info) to replace conrresponding line in your code.

Related

get the least Frequent item from array of objects

I'm trying to output [device_id] of the least frequent [device_ip_isp] from this array.
Also, If the array only has two SharedDevice Object available, and having different [device_ip_isp], it should output the 2nd SharedDevice Object's [device_id]
array (
0 =>
SharedDevice::__set_state(array(
'device_no' => 1,
'device_id' => '82',
'device_ip_isp' => 'Verizon Fios',
)),
1 =>
SharedDevice::__set_state(array(
'device_no' => 2,
'device_id' => '201',
'device_ip_isp' => 'Spectrum',
)),
2 =>
SharedDevice::__set_state(array(
'device_no' => 3,
'device_id' => '312',
'device_ip_isp' => 'Verizon Fios',
)),
3 =>
SharedDevice::__set_state(array(
'device_no' => 4,
'device_id' => '9715',
'device_ip_isp' => 'Verizon Fios',
)),
4 =>
SharedDevice::__set_state(array(
'device_no' => 5,
'device_id' => '11190',
'device_ip_isp' => 'Verizon Fios',
)),
)
The output should be 201 because "Spectrum" is the least frequent.
I tried the following and had issues:
I'm not sure how I can sort the object variables before comparing to find the least frequent.
/*
$user->getUser_devices() will output the array shown above.
*/
leastFrequent($user->getUser_devices(), 5);
function leastFrequent($arr, $n){
// find the min frequency
// using linear traversal
$min_count = $n + 1;
$res = -1;
$curr_count = 1;
for ($i = 1; $i < $n; $i++) {
if ($arr[$i]['device_ip_isp'] == $arr[$i - 1]['device_ip_isp']) {
$curr_count++;
} else {
if ($curr_count < $min_count) {
$min_count = $curr_count;
$res = $arr[$i - 1]['device_id'];
}
$curr_count = 1;
}
}
// If last element is
// least frequent
if ($curr_count < $min_count) {
$min_count = $curr_count;
$res = $arr[$n - 1]['device_id'];
}
return $arr[$n]$res['device_id'];
}
Ok, below is the explanation of the snippet inside out.
array_column to get all the device_ip_isp values in a single array.
array_count_values to get the frequency of each value.
array_reverse to reverse the count frequency array since you need the latest share device ID incase of count collision for a minimum count value.
min to get the lowest value among all the frequency counts.
array_search to get the key of the first frequency min element.
In the end, we reverse the input array to immediate return the device IP the moment we find the key from the above step matching the current device_ip_isp.
Snippet:
<?php
function getLeastFrequentElement($arr){
$freqs = array_reverse(array_count_values(array_column($arr, 'device_ip_isp')));
$deviceIPISP = array_search(min($freqs), $freqs);
foreach(array_reverse($arr) as $sharedDevice){
if($sharedDevice->device_ip_isp === $deviceIPISP){
return $sharedDevice->device_id;
}
}
throw new Exception("No shared object found!");
}
echo getLeastFrequentElement($arr);
Online Demo

Generate multi dimensional PHP array using range

The job to be done is show the price of postage per KG. So starting at 1KG, I want to increase by 0.50 for every KG.
I tried doing it like this which doesn't seem to work for me:
$shipping_second_class = array (
array ('weight' => range(1,5), 'cost' => range(1,3, 0.50))
);
foreach ($shipping_second_class as $shipping_second_class) {
echo('weight '.$shipping_second_class['weight'].' costs £'.$shipping_second_class['cost'].'<br/>');
}
That doesn't seem to work. What I'm trying to do in a way that's easier to maintain is something like this, but with less code:
$shipping_second_class = array (
array ('weight' => '1', 'cost' => '1'),
array ('weight' => '2', 'cost' => '1.5'),
array ('weight' => '3', 'cost' => '2'),
array ('weight' => '4', 'cost' => '2.5'),
array ('weight' => '5', 'cost' => '3'),
);
foreach ($shipping_second_class as $shipping_second_class) {
echo('weight '.$shipping_second_class['weight'].' costs £'.$shipping_second_class['cost'].'<br/>');
}
Another simple way
$per_kg_extra_cost = 0.5;
foreach (range(0, 4) as $shipping) {
$cost = 1 + ( $shipping * $per_kg_extra_cost );
$weight = ++$shipping;
echo '<pre>';
echo 'Weight: '. $weight . ' cost : ' .$cost;
}
Here's one way to do this:
$shipping_second_class = array (
array ('weight' => 1, 'cost' => 1)
);
for($x = 2; $x < 6; $x++){
$newdata = ['weight' => $x, 'cost' => 0.5 + $x * 0.5];
array_push($shipping_second_class, $newdata);
}
foreach ($shipping_second_class as $s) {
echo('weight '.$s['weight'].' costs £'.$s['cost'].'<br/>');
}
Essentially, you need to add to the array after it's been called rather than initialize it fully filled. You start with the array at 1 value (you could modify this code to start with an empty array) and it expands from there. If you need to add more to the array, just increase the 6 to (Desired Number) + 1 in the for loop.
I'm not sure if there is a way to add to the array in the manner you do in the first block of code.
Here is a simple way to do it:
$key = -1;
$interval = 0.5;
$shipping_second_class = array_map(function($v) use (&$key,$interval) {
$key++;
return ["weight"=>$v,"cost"=>(1 + ($interval * $key))];
},range(1,5));
echo json_encode($shipping_second_class);
You can change the $interval variable if you need to change the way it increments cost

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

How do I retrieve a random value in multidimensional associative array?

I have an array which contains information on posts I have made.
$DexArray = array(
array(
'url' => "http://i.imgur.com/ObXLdd6C.jpg",
'headline' => "Dronningens Nytårstale",
'subline' => "Tallene bag talen og årets spilforslag",
'href' => "nytaarstale.php",
'postedby' => "kris",
'postedurl' => "https://www.facebook.com/dataanalyticsdk",
'dato' => "21. december, 2014"
),
array(
'url' => "http://i.imgur.com/sxddhOe.jpg",
'headline' => "Endless Jewelry",
'subline' => "Are there really endless possibilities?",
'href' => "endless.php",
'postedby' => "Nikolaj Thulstrup",
'postedurl' => "kris",
'dato' => "10. december, 2014"
),
It is stored in a multidimensional associate array. I am trying to retrieve a random 'href' value in the array and store it as a variable.
I have tried using the array_rand function but it doesn't seem to work.
$k = array_rand($DexArray);
$v = $array[$k]['href'];
I get an error message saying: undefined variable: array in this line "$v = $array[$k]['href'];"
Do you have a solution for this?
It should be
$k = array_rand($DexArray);
$v = $DexArray[$k]['href'];
Here's a working debug :) link
There was a lingering , in your thingy. And $array was never defined in the first place, so that's what the error was telling you about.
Execute the code it will return the random value from the multidimensional php array.
<?php
$filter_field = array();
$original_items = array(
array(1, 'stuff1', 'info1', 'response1', 'info1', 'response1'), array(2, 'stuff2', 'info2', 'response2', 'info2', 'response2'), array(3, 'stuff3', 'info3', 'response3', 'info3', 'response3'), array(4, 'stuff4', 'info4', 'response4', 'info4', 'response4'));
for ($x = 0; $x < sizeof($original_items); $x++) {
array_push($filter_field, $original_items[$x][0]);
}
shuffle($filter_field);
echo "<br/><br/><br/>";
for ($x = 0; $x < sizeof($original_items); $x++) {
$k = $filter_field[$x];
for ($y = 0; $y < 5; $y++) {
echo $original_items[$k-1][$y];
}
echo "<br/><br/>";
}
?>
Here is another solution that will return the index of the random array.
$var = array(
array("a", "one"),
array("b", "two"),
array("c", "three"),
array("d", "four"),
array("e", "five"),
array("f", "six"),
array("g", "seven")
);
// array_rand returns the INDEX to the randomly
// chosen value, use that to access the array.
$finalVar = $var[array_rand($var)];
print_r($finalVar);

How to compare 2 array with same key but different value PHP

I want to ask about compare 2 arrays with same key but different value.
I have 1 array master (arrayMaster) and 2 or more array data (arrayData1, arrayData2, and maybe could be more). These array data key will have exactly one of arrayMaster data key (I've done for this thing). For data example that I get:
arrayMaster = Array( [apple] => 1 [banana] => 2 [choco] => 1 [donut] => 2 [egg] => 1 )
arrayData1 = Array( [apple] => 8 [banana] => 2 [choco] => 1 )
arrayData2 = Array( [donut] => 5 [choco] => 2 [egg] => 3 )
(We can see that arrayData1 and arrayData2 contain a key from arrayMaster key.)
These arrays I want to compare and give a calculating method. If the array key at arrayData(n) found at arrayMaster, it will do a calculating data, let said it will sum each other.
So, the result is:
arrayResult1 = 1+8 (apple have 1 from master, apple have 8 from arrayData1), 2+2, 1+1
arrayResult2 = 2+5 (donut have 2 from master, donut have 5 from arrayData2), 1+2, 1+3
So I will have 2 new array (or more, depend on how much arrayData) that contain:
arrayResult1 = ([apple] => 9 [banana] => 4 [choco] => 2);
arrayResult2 = ([donut] => 7 [choco] => 3, [egg] => 4);
Anyone know how to do this? I’”ve tried array_intersect but it didn’t work.
Do something like this:
function doCalc($master, $slave) {
$results = array();
foreach( $slave as $key => $value ) {
if( !isset($master[$key]) ) {
$results[$key] = $value;
}
else {
$results[$key] = $master[$key] + $value;
}
}
return $results;
}
$arrayResult1 = doCalc($arrayMaster, $arrayData1);
$arrayResult2 = doCalc($arrayMaster, $arrayData2);
You can write something simpler like this..
function modifyArr(&$arr,$basearray) //<=-- See I am passing & (reference) so your original array will be modified
{
foreach($arr as $k=>$v)
{
if(array_search($k,$basearray)!==null)
{
$arr[$k]=$basearray[$k]+$arr[$k];
}
}
}
modifyArr($arrayData1,$arrayMaster); //<=-- Pass your 1st array
modifyArr($arrayData2,$arrayMaster); //<=-- Pass your 2nd array
Demonstration
Using these as examples:
arrayResult1 = 1+8 (apple have 1 from master, apple have 8 from arrayData1), 2+2, 1+1
arrayResult2 = 2+5 (donut have 2 from master, donut have 5 from arrayData2), 1+2, 1+3
Why not just do this:
// The main arrays for master & data values.
$arrayMaster = array('apple' => 1, 'banana' => 2, 'choco' => 1, 'donut' => 2, 'egg' => 1);
$arrayData1 = array('apple' => 8, 'banana' => 2, 'choco' => 1);
$arrayData2 = array('donut' => 5, 'choco' => 2, 'egg' => 3);
// Set a values to check array.
$values_to_check = array('apple', 'donut');
// Init the results array.
$results_array = array();
// Roll through the values to check.
foreach ($values_to_check as $value) {
// Check if the array key exists in '$arrayMaster'.
if (array_key_exists($value, $arrayMaster)) {
// If it exists, add it to the '$results_array'.
$results_array[$value][] = $arrayMaster[$value];
// Check if the array key exists in '$arrayData1'.
if (array_key_exists($value, $arrayData1)) {
// If it exists, add it to the '$results_array'.
$results_array[$value][] = $arrayData1[$value];
}
// Check if the array key exists in '$arrayData2'.
if (array_key_exists($value, $arrayData2)) {
// If it exists, add it to the '$results_array'.
$results_array[$value][] = $arrayData2[$value];
}
}
}
// Roll through the results array and use 'array_sum' to get a sum of values.
foreach ($results_array as $results_key => $results_value) {
echo $results_key . ' : ' . array_sum($results_value) . '<br />';
}
But looking at your example, I am unclear on why you have separate arrays for $arrayData1 and $arrayData2 so here is the same code, but refactored to have nested arrays in $arrayData which should be more efficient:
// The main arrays for master & data values.
$arrayMaster = array('apple' => 1, 'banana' => 2, 'choco' => 1, 'donut' => 2, 'egg' => 1);
$arrayData = array();
$arrayData[] = array('apple' => 8, 'banana' => 2, 'choco' => 1);
$arrayData[] = array('donut' => 5, 'choco' => 2, 'egg' => 3);
// Set a values to check array.
$values_to_check = array('apple', 'donut');
// Init the results array.
$results_array = array();
// Roll through the values to check.
foreach ($values_to_check as $value) {
// Check if the array key exists in '$arrayMaster'.
if (array_key_exists($value, $arrayMaster)) {
// If it exists, add it to the '$results_array'.
$results_array[$value][] = $arrayMaster[$value];
// Roll through the values to check.
foreach ($arrayData as $arrayData_value) {
// Check if the array key exists in '$arrayData1'.
if (array_key_exists($value, $arrayData_value)) {
// If it exists, add it to the '$results_array'.
$results_array[$value][] = $arrayData_value[$value];
}
}
}
}
// Roll through the results array and use 'array_sum' to get a sum of values.
foreach ($results_array as $results_key => $results_value) {
echo $results_key . ' : ' . array_sum($results_value) . '<br />';
}

Categories