How to fetch one array value from the array? - php

Hi I have array like this
Array (
[0] => stdClass Object (
[id] => 1930 [value] => 20)
[1] => stdClass Object (
[id] => 1931 [value] => 30 )
[2] => stdClass Object (
[id] => 1937 [value] => 30 )
[3] => stdClass Object (
[id] => 1938 [value] => 20 )
)
I want to fetch random array from this. The Id which has greater value(%) should be fetched more time (That value is %).

Make a another array and repeat the index of array for the number of times its value is and then fetch the values randomly this would do what you want
The above mentioned array would be
array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,)

$arr = Array (
(Object) array (id => 1930, value => 20),
(Object) array (id => 1931, value => 30),
(Object) array (id => 1937, value => 30),
(Object) array (id => 1938, value => 20));
// count sum of all values
$sum = array_reduce($arr, function ($c, $i) { return $c += $i->value; }, 0);
// get random
$rand = mt_rand(0, $sum);
echo $rand . " ";
// select 1st item that sum of values >= random value
$new = array_filter($arr, function ($i) use (&$rand) { if($rand > 0 && ($rand -= $i->value) <= 0) return true; else return false; });
// change key to 0
$new = array_values($new);
echo $new[0]->id;

One way to solve this is to make a list of the cummulative sum of the values in the array, for instance if the values are 3, 1, and 2 the cummulative sums would be 3, 4 and 6. Then when you want to get a random element, you generate a random integer between 1 maximum sum, and then pick the element whose cumulative sum is largest of those whos cumulative sum is smaller than or equal to the random number. In that way, the chanse of any element being picked is proportional to its value.
So here is the setup, creating the cumulative sums:
var $cumsum = array();
var $sum = 0;
foreach($array as $obj) {
$sum += $obj->value;
array_push($cumsum, $sum);
}
var $maxsum = end($cumsum);
And here is the function actually picking an element:
function getRandomObject() {
var $r = random(1, $max);
if($r < $cumsum[0]) return $array[0];
for($i = 0; $i < count($cumsum); $i++)
if($cumsum[$i]) > $r)
return $array[$i--];
return $array[$i];
}
Disclaimar: I have not tested this code, so don't expect it to run on a copy paste. Also, whatever code you use you should probably make sure it returns elements with the right probability using a monte carlo method.

Related

How to check if value is equal to string in array

I want to check if the value: diam-mm exist in array, if the value not exist do something.
A array can have multiple properties, property name is: [PropertyType]->[Name]
i thought i loop to the properties and check if diam-mm value exist, else do something but because of the loop he does import the value mutliple times instead of one time.
Example of one array with properties:
[2] => Array
(
[PropertyType] => Array
(
[Guid] =>
[DataType] => Text
[Name] => diam-mm
[Unit] =>
)
[BooleanValue] =>
[DateTimeValue] =>
[NumericValue] =>
[TextValue] => 400
[XmlValue] =>
[UrlValue] => 400
)
[3] => Array
(
[PropertyType] => Array
(
[Guid] =>
[DataType] => Text
[Name] => lengte-mm
[Unit] =>
)
[BooleanValue] =>
[DateTimeValue] =>
[NumericValue] =>
[TextValue] => 2000
[XmlValue] =>
[UrlValue] => 2000
)
<?php
for ($i=0; $i <count($array) ; $i++) {
if($array[$i]['PropertyType']['Name']=="diam-mm"){
// your code
}
}
?>
If you want to check if an array key matches a value you can do so using simple variable assignment. However you would need to loop through each array index item and enumarate the loop based on it's iteration.
To create the loop I would suggest using count to count the amount of items in the array. We will assign the result to a variable :
$count = count($my_array);
Do keep in mind that count only counts the number of items based on their actual count, not their array index. This means that an array with indexes starting from zero which has an index of 0-30 would return 31 as the result of count because count counted the zero index as an actual count value.
To fix this we need to subtract 1 from the result of count :
$count = $count - 1;
Then we can use the count as the number of repeats in a for loop. Where the variable $i represents the iteration that the loop is going through :
//Loop through each array index
for($i=0; $i <= $count; $i++){
//Assign the value of the array key to a variable
$value = $my_array[$i]['PropertyType']['Name'];
//Check if result string contains diam-mm
if(str_contains($value, 'diam-mm'){
echo 'The value matches!';
} else{
echo 'The value does not match!';
}
}
Try this function, i hope this answer your question...
function array_recursive_search_key_map($needle, $haystack) {
foreach($haystack as $first_level_key=>$value) {
if ($needle === $value) {
return array($first_level_key);
} elseif (is_array($value)) {
$callback = $this->array_recursive_search_key_map($needle, $value);
if ($callback) {
return array_merge(array($first_level_key), $callback);
}
}
}
return false;
}
How to use
$yourValue = "diam-mm";
$array_keymap = array_recursive_search_key_map($yourValue, $yourArray);
var_dump($array_keymap);
Output
Array
(
[0] => 0
[1] => PropertyType
[2] => Name
)

Create new array inside a multidimensional array, step up name each cycle

Question:
How can I iterate below so it checks existence of key "round_1", next script run it should check existense of key "round_2", etc. Everytime it would encounter that the key is missing it should create the key.
It is working with "round_1" as expected.
<?php
// Create array skeleton.
$array_skeleton = array_fill(1, 3, "");
print_r($array_skeleton);
// Populate the skeleton with random numbers, values [1 to 6].
foreach($array_skeleton as $key => $value) {
$populated_array[$key] = random_int(1, 6);
};
print_r($populated_array);
// Create empty array for purpose to become multidimensional array.
$scorecard = [];
// Check if [round_1] is missing, if so create [round_1] and populate it.
if(!array_key_exists("round_1", $scorecard)) {
echo "round_1 is missing, creating it";
$scorecard["round_1"] = $populated_array;
}
print_r($scorecard);
Outcome works fine as expected, after first script run:
(
[round_1] => Array
(
[1] => 3
[2] => 4
[3] => 1
)
)
Expected outcome, after second script run:
Note! It is correct that the values would be different per each round since they are randomly created.
(
[round_1] => Array
(
[1] => 3
[2] => 4
[3] => 1
)
[round_2] => Array
(
[1] => 1
[2] => 4
[3] => 2
)
)
I think your entire code can be simplify:
first define function for create array with random number:
function createRandomNumberArray($numOfElem, $maxRange) {
for ($i = 0; $i < $numOfElem; $i++)
$res[] = random_int(1, $maxRange);
return $res;
}
Second, assuming your keys are made of "round_#INT#" pattern you can do
$biggest = max(array_map(function ($e) {$p = explode("_", $e); return $p[1];}, array_keys($arr)));
And now do:
$newKey = "round_" . ($biggest + 1);
$scorecard[$newKey] = createRandomNumberArray(3,6);
Reference: array-map, explode, max, random-int

Distribute associative array elements into groups with a maximum sum per group

I need to split my associative array into bunches of not greater than 50 in each bunch. Multiple elements may be pushed into a given group to ensure that a group reaches 50 before starting a new group.
Sample input:
$array = [
'5' => 142,
'2' => 57,
'18' => 37
];
Desired result:
[
['5' => 50],
['5' => 50],
['5' => 42, '2' => 8],
['2' => 49, '18' => 1],
['18' => 36],
];
just mind games
$line = [];
// Invert array
foreach($arr as $k=>$v) {
$line = array_merge($line, array_fill(0, $v, $k));
}
// Split and count occurrences
$res = array_map('array_count_values', array_chunk($line, 50));
print_r($res);
demo
To create an array where the sum of each entry would not exceed a given amount, you can use an iterative approach.
Let's start with an empty array and a variable representing the working index of that array. As we go through the input array, we add the maximum possible remaining quantity to the new array. If we reach the limit, we increment the index variable. And we continue as long as the input array has not been completely browsed.
Code:
const MAX_SUM = 50;
$total = []; // Store the new data
$curKey = 0; // Store the current key of $total array.
foreach ($array as $key => $value) {
while ($value) {
// Get the current sum for the current key:
$curSum = array_sum($total[$curKey] ?? []);
// If the max was reached, we can go to the next key:
if ($curSum == MAX_SUM) $curKey++;
// Now, compute if the value to add (max to reach 50);
$add = $value + $curSum > MAX_SUM // If above,
? MAX_SUM - $curSum // got only the difference,
: $value; // else, use the full value.
// Add the value
$total[$curKey][$key] = $add;
// Finally, remove what we added just before.
$value -= $add;
}
}
print_r($total);
Outputs :
Array (
[0] => Array (
[5] => 50
)
[1] => Array (
[5] => 50
)
[2] => Array (
[5] => 42
[2] => 8
)
[3] => Array (
[2] => 49
[18] => 1
)
[4] => Array (
[18] => 36
)
)
See also a the nice answer of #mickmackusa.
My train of thought for this task aligns with #Syscall's "push & consume" approach.
Iterate the input array to access the keys and values.
Use an inner loop to repeatedly process the current value until it is fully consumed by subtraction. Only break the loop upon the value being reduced to zero.
With each pass of the inner loop:
Calculate the current total of all values in the group, then
Find the lesser integer value between how much room is left in the group and how much is left in the value; push that integer into the group with the current key; then subtract that integer from the current value, then
Increment the group key if the current group has reach its limit
Repeat until all input elements are reduced to zero.
Code: (Demo)
$groupLimit = 50; // declare as a variable to avoid "magic numbers" in code
$result = [];
$groupKey = 0;
foreach ($array as $key => $value) {
while ($value) {
$sum = array_sum($result[$groupKey] ?? []); // get group sum
$value -= $result[$groupKey][$key] = min($groupLimit - $sum, $value); // push key with limited value; decrease value
$groupKey += ($sum + $result[$groupKey][$key] === $groupLimit); // only increment group key if at $groupLimit
}
}
var_export($result);

PHP Is it possible to sum elements of an array?

I have an array which has multiple sets of data.
Is it possible to sum elements (not all) of the array. For example, is it possible to sum the first 5 sets of data in an array, then then next 7, then the next three etc.
EDIT:
I've tried the following but with not joy:
for ($p=0; $p<=8; $p++){
$tot = 0;
$resp = 0;
$tot = $tot + $row4['Total_Staff'];
$resp = $resp + $row4['Total_Resp'];
}
Clearly I am not using this correctly!
Array Output (print_r output):
Array ( [department] => Central>ACME>BusDev [Total_Staff] => 4 [Total_Resp] => 0 )
Array ( [department] => Central>ACME>ChemDev [Total_Staff] => 7 [Total_Resp] => 0 )
Array ( [department] => Central>ACME>Admin [Total_Staff] => 1 [Total_Resp] => 0 )
Array ( [department] => Central>ACME>Chemistry [Total_Staff] => 4 [Total_Resp] => 0 )
Use array_splice() to remove $numOfElems elements from the array and the return them. Use array_sum() to calculate the sum. Repeat the process until the array is empty.
$array = array(/* your array */)
$sets = array(5,7,3);
$sum_arr = array();
foreach ($sets as $numOfElems) {
while (!empty($array)) {
$elem_arr = array_splice($array, 0, $numOfElems);
$sum[] = array_sum($elem_arr);
}
}
print_r($sum_arr);
This will repeat the process with the same sets until it reaches the end of array. If you only want count($sets) number of iterations, then perhaps, you could change while to if.
Demo

PHP Find All (somewhat) Unique Combinations of an Array

I've been looking at PHP array permutation / combination questions all day.. and still can't figure it out :/
If I have an array like:
20 //key being 0
20 //key being 1
22 //key being 2
24 //key being 3
I need combinations like:
20, 20, 22 //keys being 0 1 2
20, 20, 24 //keys being 0 1 3
20, 22, 24 //keys being 0 2 3
20, 22, 24 //keys being 1 2 3
The code I currently have gives me:
20, 22, 24
because it doesn't want to repeat 20... but that's what I need!
Here is the code I have. it is directly from Php recursion to get all possibilities of strings
function getCombinations($base,$n){
$baselen = count($base);
if($baselen == 0){
return;
}
if($n == 1){
$return = array();
foreach($base as $b){
$return[] = array($b);
}
return $return;
}else{
//get one level lower combinations
$oneLevelLower = getCombinations($base,$n-1);
//for every one level lower combinations add one element to them that the last element of a combination is preceeded by the element which follows it in base array if there is none, does not add
$newCombs = array();
foreach($oneLevelLower as $oll){
$lastEl = $oll[$n-2];
$found = false;
foreach($base as $key => $b){
if($b == $lastEl){
$found = true;
continue;
//last element found
}
if($found == true){
//add to combinations with last element
if($key < $baselen){
$tmp = $oll;
$newCombination = array_slice($tmp,0);
$newCombination[]=$b;
$newCombs[] = array_slice($newCombination,0);
}
}
}
}
}
return $newCombs;
}
I've been playing around with the ($b == $lastEl) line, with no luck
===============
Questions I've already looked at, and are not the same OR that created an out of memory error!:
How can I get all permutations in PHP without sequential duplicates?
Permutations - all possible sets of numbers
Combinations, Dispositions and Permutations in PHP
PHP array combinations
Get all permutations of a PHP array?
PHP: How to get all possible combinations of 1D array?
Select only unique array values from this array
Get all permutations of a PHP array?
PHP: How to get all possible combinations of 1D array?
Select only unique array values from this array
How can I get all permutations in PHP without sequential duplicates?
Algorithm to return all combinations of k elements from n
Find combination(s) sum of element(s) in array whose sum equal to a given number
Combinations, Dispositions and Permutations in PHP
PHP array combinations
Php recursion to get all possibilities of strings
How to return permutations of an array in PHP?
Permutations - all possible sets of numbers
Subset-sum problem in PHP with MySQL
Find unique combinations of values from arrays filtering out any duplicate pairs
Finding all the unique permutations of a string without generating duplicates
Generate all unique permutations
Subset sum for exactly k integers?
I've tried some of these algorithms with an array of 12 items, and end up running out of memory. However the algorithm that I'm currently using doesn't give me an out of memory error.... BUT.. I need those duplicates!
If you don't mind using a couple of global variables, you could do this in PHP (translated from a version in JavaScript):
<?PHP
$result = array();
$combination = array();
function combinations(array $myArray, $choose) {
global $result, $combination;
$n = count($myArray);
function inner ($start, $choose_, $arr, $n) {
global $result, $combination;
if ($choose_ == 0) array_push($result,$combination);
else for ($i = $start; $i <= $n - $choose_; ++$i) {
array_push($combination, $arr[$i]);
inner($i + 1, $choose_ - 1, $arr, $n);
array_pop($combination);
}
}
inner(0, $choose, $myArray, $n);
return $result;
}
print_r(combinations(array(20,20,22,24), 3));
?>
OUTPUT:
Array ( [0] => Array ( [0] => 20
[1] => 20
[2] => 22 )
[1] => Array ( [0] => 20
[1] => 20
[2] => 24 )
[2] => Array ( [0] => 20
[1] => 22
[2] => 24 )
[3] => Array ( [0] => 20
[1] => 22
[2] => 24 ) )
The pear package Math_Combinatorics makes this kind of problem fairly easy. It takes relatively little code, it's simple and straightforward, and it's pretty easy to read.
$ cat code/php/test.php
<?php
$input = array(20, 20, 22, 24);
require_once 'Math/Combinatorics.php';
$c = new Math_Combinatorics;
$combinations = $c->combinations($input, 3);
for ($i = 0; $i < count($combinations); $i++) {
$vals = array_values($combinations[$i]);
$s = implode($vals, ", ");
print $s . "\n";
}
?>
$ php code/php/test.php
20, 20, 22
20, 20, 24
20, 22, 24
20, 22, 24
If I had to package this as a function, I'd do something like this.
function combinations($arr, $num_at_a_time)
{
include_once 'Math/Combinatorics.php';
if (count($arr) < $num_at_a_time) {
$arr_count = count($arr);
trigger_error(
"Cannot take $arr_count elements $num_at_a_time "
."at a time.", E_USER_ERROR
);
}
$c = new Math_Combinatorics;
$combinations = $c->combinations($arr, $num_at_a_time);
$return = array();
for ($i = 0; $i < count($combinations); $i++) {
$values = array_values($combinations[$i]);
$return[$i] = $values;
}
return $return;
}
That will return an array of arrays. To get the text . . .
<?php
include_once('combinations.php');
$input = array(20, 20, 22, 24);
$output = combinations($input, 3);
foreach ($output as $row) {
print implode($row, ", ").PHP_EOL;
}
?>
20, 20, 22
20, 20, 24
20, 22, 24
20, 22, 24
Why not just use binary? At least then its simple and very easy to understand what each line of code does like this? Here's a function i wrote for myself in a project which i think is pretty neat!
function search_get_combos($array){
$bits = count($array); //bits of binary number equal to number of words in query;
//Convert decimal number to binary with set number of bits, and split into array
$dec = 1;
$binary = str_split(str_pad(decbin($dec), $bits, '0', STR_PAD_LEFT));
while($dec < pow(2, $bits)) {
//Each 'word' is linked to a bit of the binary number.
//Whenever the bit is '1' its added to the current term.
$curterm = "";
$i = 0;
while($i < ($bits)){
if($binary[$i] == 1) {
$curterm[] = $array[$i]." ";
}
$i++;
}
$terms[] = $curterm;
//Count up by 1
$dec++;
$binary = str_split(str_pad(decbin($dec), $bits, '0', STR_PAD_LEFT));
}
return $terms;
}
For your example, this outputs:
Array
(
[0] => Array
(
[0] => 24
)
[1] => Array
(
[0] => 22
)
[2] => Array
(
[0] => 22
[1] => 24
)
[3] => Array
(
[0] => 20
)
[4] => Array
(
[0] => 20
[1] => 24
)
[5] => Array
(
[0] => 20
[1] => 22
)
[6] => Array
(
[0] => 20
[1] => 22
[2] => 24
)
[7] => Array
(
[0] => 20
)
[8] => Array
(
[0] => 20
[1] => 24
)
[9] => Array
(
[0] => 20
[1] => 22
)
[10] => Array
(
[0] => 20
[1] => 22
[2] => 24
)
[11] => Array
(
[0] => 20
[1] => 20
)
[12] => Array
(
[0] => 20
[1] => 20
[2] => 24
)
[13] => Array
(
[0] => 20
[1] => 20
[2] => 22
)
[14] => Array
(
[0] => 20
[1] => 20
[2] => 22
[3] => 24
)
)
Had the same problem and found a different and bitwise, faster solution:
function bitprint($u) {
$s = array();
for ($n=0; $u; $n++, $u >>= 1){
if ($u&1){
$s [] = $n;
}
}
return $s;
}
function bitcount($u) {
for ($n=0; $u; $n++, $u = $u&($u-1));
return $n;
}
function comb($c,$n) {
$s = array();
for ($u=0; $u<1<<$n; $u++){
if (bitcount($u) == $c){
$s [] = bitprint($u);
}
}
return $s;
}
This one generates all size m combinations of the integers from 0 to n-1, so for example
m = 2, n = 3 and calling comb(2, 3) will produce:
0 1
0 2
1 2
It gives you index positions, so it's easy to point to array elements by index.
Edit: Fails with input comb(30, 5). Have no idea why, anyone any idea?
Cleaned up Adi Bradfield's sugestion using strrev and for/foreach loops, and only get unique results.
function search_get_combos($array = array()) {
sort($array);
$terms = array();
for ($dec = 1; $dec < pow(2, count($array)); $dec++) {
$curterm = array();
foreach (str_split(strrev(decbin($dec))) as $i => $bit) {
if ($bit) {
$curterm[] = $array[$i];
}
}
if (!in_array($curterm, $terms)) {
$terms[] = $curterm;
}
}
return $terms;
}
The Idea is simple. Suppose you know how to permute, then if you save these permutations in a set it becomes a combinations. Set by definition takes care of the duplicate values. The Php euqivalent of Set or HashSet is SplObjectStorage and ArrayList is Array. It should not be hard to rewrite. I have an implementation in Java:
public static HashSet<ArrayList<Integer>> permuteWithoutDuplicate(ArrayList<Integer> input){
if(input.size()==1){
HashSet<ArrayList<Integer>> b=new HashSet<ArrayList<Integer>>();
b.add(input);
return b;
}
HashSet<ArrayList<Integer>>ret= new HashSet<ArrayList<Integer>>();
int len=input.size();
for(int i=0;i<len;i++){
Integer a = input.remove(i);
HashSet<ArrayList<Integer>>temp=permuteWithoutDuplicate(new ArrayList<Integer>(input));
for(ArrayList<Integer> t:temp)
t.add(a);
ret.addAll(temp);
input.add(i, a);
}
return ret;
}

Categories