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
Related
I have a quiz where you can use text field or radio buttons for the answers. The answers are stored in a database. None of the answers are required so people can skip questions.
Each entry is stored in a row:
Array
(
[0] => Array
(
[0] => Dave
[1] => ok
[2] => Manchester
[3] => No
)
[1] => Array
(
[0] => James
[1] => Happy
[2] => London
[3] => Yes
)
[2] => Array
(
[0] => Victoia
[2] => Leeds
)
)
Currently the question number is represented by the key. So Victoria hasn't answered question 1 or 3. My aim is to add the unanswered into the array witht the correct key value being null.
Here is my code so far but I'm struggling to get the array key position correct:
$answersArr = (array) $answers;
$row = array();
$items = array();
$numberOfQuesitons = count($headers);
foreach ($answersArr as $key=>$result) {
$answer = json_decode(stripslashes($result->answers));
$row[$key] = (array) $answer;
$single = count($row[$key]);
$currentKey = key($row[$key]);
for ($i = $single ; $i < $numberOfQuesitons; $i++) {
if ($numberOfQuesitons - $i > 0) {
if ($currentKey > 0) {
array_unshift($row[$key], null);
} else {
array_push($row[$key], null);
}
}
}
}
print_r($row);
The out put I get:
Array
(
[0] => Array
(
[0] => Admin
[1] => ok
[2] => Manchester
[3] => No
)
[1] => Array
(
[0] => Rod
[1] => Happy
[2] => London
[3] => Yes
)
[2] => Array
(
[0] => Rozi
[2] => Leeds
[3] =>
[4] =>
)
)
The last row in the array needs to look like this:
[2] => Array
(
[0] => Victoia
[1] =>
[2] => Somewhere
[3] =>
)
A little stuck here any help would be much appreciated.
Thanks
Let me say that I read through your code and have to make two assumptions: $numberOfQuesitons = 4 and $single = 2 in the case of Victoia.
Assumption is based on the fact that the name of a person is included in the result arrays and otherwise could not be derived.
So in your code at the iteration of Victoia we will have the following array to work with:
$row[$key] = [
0 => 'Victoia',
2 => 'Leeds',
];
Then at the inner for loop the following will happen (as noted in comments):
for ($i = $single; $i < $numberOfQuesitons; $i++) {
// 4 - 2 = 2, 2 > 0 = true <-- first iteration
// 4 - 3 = 1, 1 > 0 = true <-- second (and final) iteration
if ($numberOfQuesitons - $i > 0) {
// $currentKey doesn't change in this process
// and since the key is taken from the array
// $row[$key] points to, the key function will return 0 each iteration.
if ($currentKey > 0) {
// Also note that unshift will only add elements to the front of the array.
array_unshift($row[$key], null);
} else {
// Hence we drop down in this branch of the if statemtent
// as 0 > 0 evaluates to false each evaluation.
// So we start with [0] => Rozi || Victoia
// [2] => Leeds || Somewhere
// Push null thus: [3] => null
// Push null thus: [4] => null
// Hence our final result.
// Also note that push only 'pushes' elements at the end of the array.
array_push($row[$key], null);
}
}
}
To solve this we could change the logic a little bit, but personally I would modify the nested loop to the following (or something similar):
$answersArr = (array) $answers;
$row = array();
$numberOfQuesitons = count($headers);
foreach ($answersArr as $key => $result) {
$answer = json_decode(stripslashes($result->answers));
$row[$key] = (array) $answer;
// We simply create a range from 0 up to the last question number.
$all = range(0, $numberOfQuesitons - 1);
// Taking the difference between all questions and the answered
// ones will give us the missing ones.
$unAnsweredQs = array_diff($all, array_keys($row[$key]));
// Add those missing questions to the array.
foreach ($unAnsweredQs as $unAnswered) {
// Or maybe a more appropriate default.
$row[$key][$unAnswered] = null;
}
// Sort the keys, such that we respect the wanted order
// Name (key 0), Q1, Q2, ..., QN
ksort($row[$key]);
}
print_r($row);
I have an array of elements which I queried from the mongoDB.
This array has the id of a device and value of this device's consumptions.
For example there are 3 different ids -> 18,5,3 and multiple mixed values.
// first record of 18 so get value.
$row[0]["id"] = 18;
$row[0]["value"] = 100;
// not first record of 18 so ignore and move to the next record
$row[1]["id"] = 18;
$row[1]["value"] = 40;
// first record of 5 so get value.
$row[2]["id"] = 5;
$row[2]["value"] = 20;
// not first record of 18 so ignore and move to the next record
$row[3]["id"] = 18;
$row[3]["value"] = 30;
// first record of 3 so get value.
$row[4]["id"] = 3;
$row[4]["value"] = 20;
//not first record of 5 so ignore and move to the next record**
$row[5]["id"] = 5;
$row[5]["value"] = 30;
// not first record of 18 so ignore and move to the next record
$row[6]["id"] = 18;
$row[6]["value"] = 10;
...
....
What I am trying to do is loop through this $row array and get the most recent value of the id.
For example in above example what I want to return is:
id value
18 100
5 20
3 20
How can I do that kind of logic?
It can be done in several ways. The easiest one is to use a foreach:
$result = array();
foreach ($row as $i) {
if (! array_key_exists($i['id'], $result)) {
$result[$i['id']] = $i['value'];
}
}
# Verify the result
print_r($result);
The output is:
Array
(
[18] => 100
[5] => 20
[3] => 20
)
The same processing, but using array_reduce():
$result = array_reduce(
$row,
function(array $c, array $i) {
if (! array_key_exists($i['id'], $c)) {
$c[$i['id']] = $i['value'];
}
return $c;
},
array()
);
If you want to keep only the first occurrence of each 'id' then just add the values to an aggregate array - but only if they haven't been added already. Then grab the values of the aggregate array.
https://tehplayground.com/NRvw9uJF615oeh6C - press Ctrl+Enter to run
$results = array();
foreach ($row as $r) {
$id = $r['id'];
if (! array_key_exists($id, $results)) {
$results[$id] = $r;
}
}
$results = array_values($results);
print_r($results);
Array
(
[0] => Array
(
[id] => 18
[value] => 100
)
[1] => Array
(
[id] => 5
[value] => 20
)
[2] => Array
(
[id] => 3
[value] => 20
)
)
Try this
$alreadyfound = []; // empty array
$result = [];
foreach ($row as $item)
{
if (in_array($item["id"], $alreadyfound))
continue;
$alreadyfound[] = $item["id"]; // add to array
$result[] = $item;
}
The result
Array
(
[0] => Array
(
[id] => 18
[value] => 100
)
[1] => Array
(
[id] => 5
[value] => 20
)
[2] => Array
(
[id] => 3
[value] => 20
)
)
The array_unique() function is exactly what you are looking at.
See the documentation here : array_unique() documentation
Using array_column with an index key will almost do it, but it will be in the reverse order, so you can reverse the input so that it works.
$result = array_column(array_reverse($row), 'value', 'id');
$champions array =
Array (
[0] => Shen
[1] => Graves
[2] => Lux
[3] => Tristana
[4] => Janna
[5] => Lissandra
[6] => RekSai
[7] => Anivia
[8] => Lucian
[9] => Alistar )
This array has always 10 values.
$fbps array =
Array (
[0] => RekSai
[1] => Alistar
[2] => Lucian )
This array has always 1-5 values.
What i want to make
Array (
[0] => 0
[1] => 0
[2] => 0
[3] => 0
[4] => 0
[5] => 0
[6] => 1
[7] => 0
[8] => 1
[9] => 1 )
My english is bad to explain this, i hope arrays are enough to tell. Sorry for bad title and explanation.
Edit: Ill try to explain it more. For example Shen's key is 0 in first array. $fbps array doesnt have a value named "Shen" so in third array 0 => 0. Lucian's key is 8 in first array. fbps have a value named Lucian. So third arrays 8th key has value "1"
$cArr = array('Shen','Graves','Lux','Tristana','Janna','Lissandra','RekSai','Anivia','Lucian','Alistar');
$fbps = array('RekSai','Anivia','Lucian');
foreach ($cArr as $key=>$value) {
if(array_search($value, $fbps) !== false) {
$cArr[$key] = 1;
} else {
$cArr[$key] = 0;
}
}
var_dump($cArr);
Or a more compact version:
$cArr = array('Shen','Graves','Lux','Tristana','Janna','Lissandra','RekSai','Anivia','Lucian','Alistar');
$fbps = array('RekSai','Anivia','Lucian');
foreach ($cArr as $key=>$value) {
$cArr[$key] = (array_search($value, $fbps) !== false) ? 1 : 0;
}
var_dump($cArr);
EDIT:
added in the !== false conditional as matches found in position 0 of the $fbps array incorrectly evaluated to false because 0 also = false in PHP land...
EDIT 2:
This function has O(N) complexity, meaning it'll grow linearly and in direct proportion to the size of the input data set.
Does the resulting array just have a value of 1 for every element of $fbps that appears in $champions? If so, something like this should do it;
$champions = ['Shen', 'Graves', 'Alister', '...'];
$fbps = ['Shen', 'Alister', '...'];
$result = array_map(function($value) use ($fbps) {
return (int)in_array($value, $fbps);
}, $champions);
I know you've already accepted an answer but here is the most efficient solution:
<?php
// Your arrays
$champions = array('Shen','Graves','Lux','Tristana','Janna','Lissandra','RekSai','Anivia','Lucian','Alistar');
$fbps = array('RekSai','Alistar','Lucian');
// New array which will store the difference
$champ_compare = array();
// Flip the array so that it is associative and uses the names as keys
// http://php.net/manual/en/function.array-flip.php
$fbps = array_flip($fbps);
// Loop all champions and use $v as reference
foreach($champions as &$v)
{
// Check for the existent of $v in the associative $fbps array
// This is leaps and bounds faster than using in_array()
// Especially if you are running this many times with an unknown number of array elements
$champ_compare[] = (int)isset($fbps[$v]);
}
unset($v);
// Flip it back if you need to
$fbps = array_flip($fbps);
print_r($champ_compare);
If you just want the most compact code and do not care about performance then you can try this:
<?php
// Your arrays
$champions = array('Shen','Graves','Lux','Tristana','Janna','Lissandra','RekSai','Anivia','Lucian','Alistar');
$fbps = array('RekSai','Alistar','Lucian');
// New array which will store the difference
$champ_compare = array();
// Loop all champions and use $v as reference
foreach($champions as &$v)
{
// Check if the current champion exists in $fbps
$champ_compare[] = (int)in_array($v, $fbps);
}
unset($v);
print_r($champ_compare);
Not as detailed as Garry's answer, but is based on your existing arrays.
$res = array()
foreach($champions as $key => $val) {
$res[$key] = (in_array($val, $fbps)) ? 1 : 0;
}
var_dump($res)
Edit: I've switched the array_key_exists to in_array.
<?php
$champions = array('Shen', 'Graves', 'Lux', 'Tristana', 'Janna', 'Lissandra', 'RekSai', 'Anivia', 'Lucian', 'Alistar');
$fbps = array('RekSai', 'Alistar', 'Lucian');
$res = array();
foreach($champions as $key => $val) {
$res[$key] = (in_array($val, $fbps)) ? 1 : 0;
}
var_dump($res);
I'm probably [super]overthinking this. I'm trying to analyze an array with values like [1,9], [4,6] [5,5], [6,4], [9,1] and duplicate digits (I'm having a super brain fart and can't even remember the term for numbers like this) remove (the last two) so that only [1,9], [4,6] [5,5] are printed.
I was thinking that turning this array into a string and using preg_match, but I'm pretty sure this wouldn't work even if I had the correct regex.
If you have an array of pairs like this:
$x = array(
array(1,9),
array(4,6),
array(5,5),
array(6,4),
array(9,1)
);
Here is one way to get the unique pairs:
foreach ($x as $pair) {
sort($pair);
$unique_pairs[implode(',', $pair)] = $pair;
}
This uses string representations of each sorted pair as keys in a new array, so the result will have distinct values by definition.
As far as the printing them out part of your question, once you have the unique values you can loop over them and print them out in whichever format you like, for example:
foreach ($unique_pairs as $pair) { vprintf("[%d,%d]<br>", $pair); }
It looks like elements are distributed symmetrically.
We can cut the array in two halves and get only the first half with array_slice():
$array = array(
array(1,9),
array(4,6),
array(5,5),
array(6,4),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 4
[1] => 6
)
[2] => Array(
[0] => 5
[1] => 5
)
)
Demo at Codepad.
ceil() is used to round the number up to the next highest integer if there is an even number of items in the array. Example: if there is 3 items in the array, 5 / 2 will return 2.5, we want 3 items so we use ceil(2.5) which gives 3.
Example with 3 items:
$array = array(
array(1,9),
array(5,5),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 5
[1] => 5
)
)
Example with 4 items:
$array = array(
array(1,9),
array(7,7),
array(7,7),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 7
[1] => 7
)
)
If I'm correct in understanding what you are trying to do, you want to remove the final 2 elements from the array?
There is a function in PHP called array_pop that removes the final element from the array.
$array = array_pop($array);
So if you run this twice, you will remove the final 2 elements from the array.
This is how I'd do it (and I hope I am not overthinking this :))
$stringArray = array();
$stringArray[] = '1,9';
$stringArray[] = '4,6';
$stringArray[] = '5,5';
$stringArray[] = '6,4';
$stringArray[] = '9,1';
foreach($stringArray as &$numString) {
$numString = explode(',', $numString);
usort($numString, function($a, $b) {return $a - $b;});
$numString = implode(',', $numString);
}
$a = array_unique($a);
print_r($a);
You basically explode every element into a subarray, sort it and then implode it back. After calling the array_unique, you're left with unique values in the array.
The output would be
Array
(
[0] => 1,9
[1] => 4,6
[2] => 5,5
)
The result you suggest treats [a,b] as equivalent to [b,a] which makes the problem a lot more complex. The code below gives the result you asked for, but without really understanding what the problem is that you are trying to fix and whether [1,9] is equivalent to [9,1] in the solution:
$a=array(array(1,9),array(4,6),...
$dup=array();
for ($i=0; $i<count($a) -1; $i++) {
for ($j=$i+1; $j<count($a); $j++) {
if (($a[$i][0]==$a[$j[0] && $a[$i][1]==$a[$j[1])
|| ($a[$i][0]==$a[$j[1] && $a[$i][1]==$a[$j[0])) {
$dup[]=$j;
}
}
}
foreach ($dup as $i) {
unset($a[$i]);
}
So I'm actually going to assume your question to have a different meaning than everyone else did. I believe what you're asking is:
How do you filter out array items where a reverse of the item has already been used?
<?php
// The example set you gave
$numberSets = [[1, 9], [4, 6], [5, 5], [6, 4], [9, 1]];
// Initialize an empty array to keep track of what we've seen
$keys = [];
// We use array filter to get rid of items we don't want
// (Notice that we use & on $keys, so that we can update the variable in the global scope)
$numberSets = array_filter($numberSets, function($set) use(&$keys) {
// Reverse the array
$set = array_reverse($set);
// Create a string of the items
$key = implode('', $set);
// Get the reverse of the numbers
$reversedKey = strrev($key);
// If the palindrome of our string was used, return false to filter
if (isset($keys[$reversedKey])) {
return false;
}
// Set the key so it's not used again
// Since $keys is being passed by reference it is updated in global scope
$keys[$key] = true;
// Return true to NOT filter this item, since it or it's reverse were not matched
return true;
});
var_dump($numberSets);
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