Creating not-so-random list from given array in PHP - php

I need to generate list of n ($size_of_list) names...
Possible members are given in array ($names_list) which gives name and chances of appearance of that name. So it is an array of 40 arrays of string and integer:
$names_list = array (
0 => array ('name' => "Mike", 'frequency' => 8),
1 => array ('name' => "Jane", 'frequency' => 7),
2 => array ('name' => "Leopold", 'frequency' => 1),
3 => array ('name' => "George", 'frequency' => 5),
...
39 => array ('name' => "Mark", 'frequency' => 6)
)
$names_list[0] = array('name' => "Mike", 'frequency' => 8) means that $name="Mike" has $frequency (or chance) of 8, and "Leopold" has chance value 1 - small chance to appear...

Specify $size_of_list and check out $result in the end. This uses random depending on weight.
$result = array();
$total = 0;
foreach ($names_list as $row) {
$total += $row['frequency'];
}
$max = mt_getrandmax();
$pre_sum = $total / $max;
for ($i = 0; $i < $size_of_list; ++$i) {
$sum = $pre_sum * mt_rand(0, $max); // $sum = $total * (mt_rand(0, $max)/$max);
foreach ($names_list as $row) {
if (($sum -= $row['frequency']) < 0) {
$result[] = $row['name'];
break;
}
}
}
var_dump($result);

My idea is to expand array with new value 'rnd' which represents sum of $frequency and previous elements rnd (where first element 'rnd' is first element's 'frequency')
$names_list[0]['rnd'] = $names_list[0]['frequency'];
for ($i=1; $i<count($names_list); $i++)
$names_list[$i]['rnd'] = $names_list[$i]['frequency'] + $names_list [$i-1]['rnd'];
and expanded array would look like this:
$names_list = array (
0 => array ('name' => "Mike", 'frequency' => 8, 'rnd' => 8),
1 => array ('name' => "Jane", 'frequency' => 7, 'rnd' => 15),
2 => array ('name' => "Leopold", 'frequency' => 1, 'rnd' => 16),
3 => array ('name' => "George", 'frequency' => 5, 'rnd' => 21),
//... other elements
39 => array ('name' => "Mark", 'frequency' => 8, 'rnd' => $sum_of_all_frequencies)
)
And then set $rand_max to value of last elements 'rnd', and then to create finale list by
comparing $random and all 'rnd' values...
$rand_max = $names_list[count($names_list)-1]['rnd'];
for ($i=1; $i<$size_of_list; $i++)
{
$random = rand (1, $rand_max);
$result = $names_list[0]['name'];
foreach ($names_list as $key => $val)
if ( ($random) > ($val['rnd']) )
$result = $names_list[$key+1]['name'];
$list[$i] = $result;
}
This solution works, but i think there are better (smarter) ways...
I would appreciate any help/suggestion...

Related

How to subtract all column values in multi-dimensional array in Php?

How can I subtract all the columns values? My array is like
Array
(
[0] => Array
(
[id] => 1
[web_traffic] => 442
[form_users] => 131
[date] => 20181004
)
[1] => Array
(
[id] => 2
[web_traffic] => 102
[form_users] => 15
[date] => 20181003
)
[2] => Array
(
[id] => 3
[web_traffic] => 387
[form_users] => 97
[date] => 20181002
)
)
I need to subtract the each column(except date & id) and get the result based on date(Ascending order). For example 20181004 means 4th October 2018. My output should like the below
Array
(
[web_traffic] => -152
[form_users] => -49
)
My code took reference from How to sum all column values in multi-dimensional array?
foreach ($data as $value) {
unset($value[ 'id' ]);
$time = date('Ymd', strtotime($value[ 'date' ]));
if (in_array($time, $dates)) {
$value[ 'date' ] = $time;
foreach ($value as $key => $secondValue) {
if ( !isset($output[ $key ])) {
$output[ $key ] = 0;
}
$output[ $key ] -= $secondValue;
}
}
}
Use PHP array_reduce() and array_column() like this:
$initial_array = array(array('id' => 1,
'web_traffic' => 442,
'form_users' => 131,
'date' => 20181004),
array('id' => 2,
'web_traffic' => 102,
'form_users' => 15,
'date' => 20181003),
array('id' => 3,
'web_traffic' => 387,
'form_users' => 97,
'date' => 20181002));
function sum($carry, $item)
{
$carry -= $item;
return $carry;
}
$web_traffic = array_column($initial_array, "web_traffic");
$form_users = array_column($initial_array, "form_users");
$date = array_column($initial_array, "date");
array_multisort($date, SORT_ASC, $form_users, SORT_DESC, $initial_array);
$result_array = Array(
"web_traffic" => array_reduce(array_column($initial_array, "web_traffic"), "sum",2*$initial_array[0]['web_traffic']),
"form_users" => array_reduce(array_column($initial_array, "form_users"), "sum",2*$initial_array[0]['form_users'])
);
print_r($result_array);
I would first sort the array using usort() in example.
Sorting first, because that can be tricky to substract in 1 loop the oldest datas to the newers one.
Separating intentions provide a cleaner code, easier to maintain.
The dates don't need to be converted into a date. The string is well formatted and can be used as is in a comparison and a sort. "20170101" < "20180101", "20180101" < "20181001" and "20181002" < "20181004"
When done, I'll save the first values as initial values to be used in substract.
Then, loop the sorted array and substract the 'web_traffic' and 'form_users' to the initial values.
$datas = array(array('id' => 1,
'web_traffic' => 442,
'form_users' => 131,
'date' => 20181004),
array('id' => 2,
'web_traffic' => 102,
'form_users' => 15,
'date' => 20181003),
array('id' => 3,
'web_traffic' => 387,
'form_users' => 97,
'date' => 20181002));
//If needed, you can backup the original array, because usort() will modify it.
$backUpDatas = $datas;
//Sort
usort($datas, function ($arr1, $arr2)
{
if (isset($arr1['date']) && isset($arr2['date']))
{
if ($arr1['date'] == $arr2['date'])
return (0);
return (($arr1['id'] > $arr2['id']) ? (-1) : (1));
}
});
//Initial values
$finalValues['web_traffic'] = $datas[0]['web_traffic'];
$finalValues['form_users'] = $datas[0]['form_users'];
//Substract
foreach ($datas as $key => $value)
{
if ($key > 0)
{
if (isset($value['web_traffic']))
$finalValues['web_traffic'] -= $value['web_traffic'];
if (isset($value['form_users']))
$finalValues['form_users'] -= $value['form_users'];
}
}
var_dump($finalValues);
Output :
array (size=2)
'web_traffic' => int -157
'form_users' => int -49

JSON - Display only certain data in php

This is my json data as an array, and it is in the file data.json, I tried to parse the data using php, but I am not able show the result using a for loop.
array (
'data' =>
array (
0 =>
array (
'a' => 3222,
'b' => 3,
),
1 =>
array (
'a' => 3221,
'b' => 3,
),
2 =>
array (
'a' => 2215,
'b' => 2,
),
3 =>
array (
'a' => 2214,
'b' => 2,
),
4 =>
array (
'a' => 3218,
'b' => 2,
),
5 =>
array (
'a' => 3217,
'b' => 3,
),
6 =>
array (
'a' => 3216,
'b' => 3,
),
7 =>
array (
'a' => 1235,
'b' => 1,
),
8 =>
array (
'a' => 1234,
'b' => 1,
),
9 =>
array (
'a' => 1233,
'b' => 1,
),
10 =>
array (
'a' => 3213,
'b' => 3,
)
)
I want to display only the data, which is "b=3" which contains the maximum value of "a".
Here is my code, which displays all the results of "a" as a string. All the data is shown as a list.
<?php
$json = file_get_contents('data.json');
$data = json_decode($json,true);
$q = $data['data'];
$length = count($q);
for ($i = 0; $i<$length ; $i++){
if ($q[$i]['b']==3){
$pc = $q[$i]['a'];
echo $pc;
echo "<br>";
}
}
This is not the result I was expected.
One way to solve this could be to check the current value of $pc against the latest value;
If that is higher, then overwrite it:
$q = $data['data'];
$length = count($q);
$max = 0;
for ($i = 0; $i<$length ; $i++){
if ($q[$i]['b']==3){
$pc = $q[$i]['a'];
if ($pc > $max) {
$max = $pc;
}
}
}
echo $max; //3222
Another option could be to use array_map and max:
$result = max(array_map(function($x){
if($x['b'] === 3) return $x['a'];
}, $q
));
echo $result; //3222

php array sum key where value is same

I have an array that contains a sub-array. I want to sum the values where the key is the same and to make it in one list.
Here is my array:
$array = array( array(x1=> 1, x2 => 3, y5 => 9),
array(x1=> 3, x4 => 1, y5 => 1),
array(x1=> 1, x8 => 5, a5 => 2),
array(x1=> 2, x10 => 3)
);
And I want to have an array like :
$newarray = array(x1=>7 , x2 => 3, x4=>1, x8=>5, x10=> 3, y5=>9, y5=>1, a5=>2));
some try:
foreach($array as $key => $values)
{
foreach($values as $n_k => $n_v)
{
$newarray [$n_k] += $n_v;
}
}
The problem is you are adding a value even if it is not defined.
You can check if not set by and init the value to 0
if ( !isset($newarray[$n_k]) ) $newarray[$n_k] = 0;
Here is the complete code:
$array = array( array('x1'=> 1, 'x2' => 3, 'y5' => 9), array('x1'=> 3, 'x4' => 1, 'y5' => 1), array('x1'=> 1, 'x8' => 5, 'a5' => 2), array('x1'=> 2, 'x10' => 3, 'b5' => 5));
$newarray = array();
foreach($array as $key => $values){
foreach($values as $n_k => $n_v) {
if ( !isset($newarray[$n_k]) ) $newarray[$n_k] = 0;
$newarray[$n_k] += $n_v;
}
}
This will result to:
Array
(
[x1] => 7
[x2] => 3
[y5] => 10
[x4] => 1
[x8] => 5
[a5] => 2
[x10] => 3
[b5] => 5
)
You can first get all the keys from the array and use that in a array_column and array_sum to get your desired output.
This will probably have more benefit if the array is larger.
$array = array( array("x1" => 1, "x2" => 3, "y5" => 9),
array("x1" => 3, "x4" => 1, "y5" => 1),
array("x1" => 1, "x8" => 5, "a5" => 2),
array("x1" => 2, "x10" => 3, "b5" => 5)
);
$keys = [];
// get all keys used in $array
foreach($array as $subarr){
$keys = array_merge($keys, array_keys($subarr));
}
// $keys is now:
// array (0 => 'x1', 1 => 'x2', 2 => 'y5', 3 => 'x1', 4 => 'x4', 5 => 'y5', 6 => 'x1', 7 => 'x8', 8 => 'a5', 9 => 'x1', 10 => 'x10', 11 => 'b5')
// loop only unique keys and sum the values
foreach(array_unique($keys) as $item){
$res[$item] = array_sum(array_column($array, $item));
}
var_dump($res);
https://3v4l.org/WaqlG
That's not my question, but i've found this that can help you:
https://stackoverflow.com/a/14196064/9721446
You have to create a new array, and then for each equal keyid, you're going to add the value. Somethinkg like that i think it works.
if doesn't help you, take a look at this post, that's not mine too!!!!
Associative array, sum values of the same key
<?php
$input = array( array(x1=> 1, x2 => 3, y5 => 9),
array(x1=> 3, x4 => 1, y5 => 1),
array(x1=> 1, x8 => 5, a5 => 2),
array(x1=> 2, x10 => 3)
);
$final = array();
array_walk_recursive($input, function($item, $key) use (&$final){
$final[$key] = isset($final[$key]) ? $item + $final[$key] : $item;
});
print_r($final);
?>

Counting values within multidimensional arrays?

I have a large array where I basically need to count the number of uniques:
example array
The end result I am looking for something like
$result = array(
'A3D5' => array('P2' => 1, 'P3' => 1, 'P4' => 1, 'total' => 3),
'AE5S' => array('P4' => 1, 'total' => 1)
);
I've tried foreaching through but can't seem to figure out how to sort them into another key, something like $zone = "P{$array['zone']}"; $result[$zone][$prestige]++ or seems to kind of not work or just error.
$array = array(
"denizen" => array
(
"prestige" => 2,
"zone" => "A3D5",
"scope_frag" => 765
),
"생각" => array
(
"prestige" => 4,
"zone" => "A3D5",
"scope_frag" => 135
),
"Ryans" => array
(
"prestige" => 3,
"zone" => "A3D5",
"scope_frag" => 78
),
"지적인" => array
(
"prestige" => 2,
"zone" => "AE5S",
"scope_frag" => 481
)
);
foreach ($array as $group) {
$zones[$group["zone"]][] = $group["prestige"];
}
foreach ($zones as $name => $zone) {
$total = count($zone);
foreach ($zone as $prestige) {
$result[$name]["P".$prestige] += 1;
}
ksort($result[$name]);
$result[$name]["total"] = $total;
}
echo "<pre>";
print_r($result);
echo "</pre>";

Undefined offset with count()

I have an array $MyArray which has some elements which are also array (lets call them subarrays). I want to know how many elements the subarray with the most elements has. The problem is, that I don't know if the index exists:
max(
#count($MyArray[$i*7]),
#count($MyArray[$i*7+1]),
#count($MyArray[$i*7+2]),
#count($MyArray[$i*7+3]),
#count($MyArray[$i*7+4]),
#count($MyArray[$i*7+5]),
#count($MyArray[$i*7+6])
);
Struckture of $MyArray:
Array(
12 => array (
0 => array ( 0 => 0, 1 => 1, ),
1 => array ( 0 => 13, 1 => 1, ),
2 => array ( 0 => 15, 1 => 1, ),
3 => array ( 0 => 20, 1 => 1, ),
4 => array ( 0 => 69, 1 => 1, )
),
5 => array (
0 => array ( 0 => 55, 1 => 1, ),
1 => array ( 0 => 32, 1 => 1, ),
2 => array ( 0 => 12, 1 => 1, ),
3 => array ( 0 => 21, 1 => 5, )
),
....
)
Can this be done better (faster)?
edit: I know foreach and I don't want to loop over every element in this array. I just want an interval of it. # is used, because I don't know if $MyArray[$i*7 + x] is Null or an array.
$i is a element of [0, 1, 2, 3, 4] (sometimes also 5)
$biggest = 0;
foreach ($MyArray as $value) {
if ($biggest < count($value)) {
$biggest = count($value);
}
}
I see, you want the size of the biggest array in the array, correct?
Simple and old school approach:
<?php
$max = -1;
foreach($MyArray as $subarray)
{
$items = count($subarray);
if($items > $max)
$max = $items;
}
echo $max;
?>
This works best since you only want to know how many elements the subarray with the most elements has.
$max = 0;
foreach ($MyArray as $value) {
$max = max($max,count($value));
}
Try this:
$arr = array();
for ($j=0;$j<=6;$j++) {
if (isset($MyArray[$i*7+$j])) $arr[] = count($MyArray[$i*7+$j]);
}
$result = max($arr);
I don't know exactly what $i refers to though...
// get the interesting part of the array
$chunk = array_intersect_key($input_array, array_flip(range($i*7, $i*7+6)));
// max(count)
$max = $chunk ? max(array_map('count', $chunk)) : 0;

Categories