I have an PHP array that has saved users steps:
array(
'step_1' => 1,
'step_2' => 1,
'step_3' => 0,
'step_4' => 0,
'step_5' => 0
);
So, my user do step_1, and step_2, but he don't do other steps.
Now, i want to get name of first step that he don't do, it's "step_3" in this example.
But if array looks that:
array(
'step_1' => 1,
'step_2' => 1,
'step_3' => 1,
'step_4' => 1,
'step_5' => 0
);
I want to get "step_5", than i know that user don't do step_5 and i can, for exapmle redirect them to specify page. How can i get it?
You could use array_search()
See In Action
<?php
$array = array(
'step_1' => 1,
'step_2' => 1,
'step_3' => 1,
'step_4' => 0,
'step_5' => 0
);
$key = array_search(0, $array); // $key = step_4;
echo $key;
?>
You can use reset($array);
http://php.net/manual/en/function.reset.php
Return Values
Returns the value of the first array element, or FALSE if the array is empty.
Edit:
You can use array_search(0,$array);
That will return you the key of first found var. (step_5) in your case.
You can try
$step = array(
'step_1' => 1,
'step_2' => 1,
'step_3' => 0,
'step_4' => 0,
'step_5' => 0
);
var_dump(__missing($step));
var_dump($step);
Output
string 'step_3' (length=6)
array
'step_1' => int 1
'step_2' => int 1
'step_3' => int 1
'step_4' => int 0
'step_5' => int 0
Example 2
$step = array(
'step_1' => 1,
'step_2' => 1,
'step_3' => 1,
'step_4' => 1,
'step_5' => 1
);
var_dump(__missing($step));
var_dump($step);
Output
string 'step_1' (length=6)
array
'step_1' => int 1
'step_2' => int 0
'step_3' => int 0
'step_4' => int 0
'step_5' => int 0
Function used
function __missing(&$array) {
$left = array_filter($array, function ($var) {
return ($var == 1) ? false : true;
});
if (! empty($left)) {
$key = key($left);
$array[$key] = 1;
return $key;
} else {
array_walk($array, function (&$var) {
return $var = 0;
});
$key = key($array);
$array[$key] = 1;
return $key;
}
}
Related
I'm creating a custom user profile for a game (osu!) and I'm trying to get which "mods" has been used in a "top play".
The API provides a decimal number containing each mods the player used in his play.
Ex: 72 for DoubleTime+Hidden mods, since DoubleTime is 64 and Hidden 8
$hidden = 8;
$doubletime = 64;
$hiddendoubletime = ($hidden|$doubletime);
I want to, from 72 for example, know that its 8 and 64.
or even from 88 that it's 8 and 16 and 64.
I was thinking about transform 88 for example in binary (01011000), then detect all "1" positions since each "1" gives a mod.
Here : 01011000 -
the first "1" at position 4 is the Hidden mod, the second "1" a position 5 is the Hardrock mod and finally, the "1" at position 7 is the DoubleTime mod.
Then enum is the following :
enum Mods
{
None = 0,
NoFail = 1,
Easy = 2,
TouchDevice = 4,
Hidden = 8,
HardRock = 16,
SuddenDeath = 32,
DoubleTime = 64,
Relax = 128,
HalfTime = 256,
Nightcore = 512, // Only set along with DoubleTime. i.e: NC only gives 576
Flashlight = 1024,
Autoplay = 2048,
SpunOut = 4096,
Relax2 = 8192, // Autopilot
Perfect = 16384, // Only set along with SuddenDeath. i.e: PF only gives 16416
Key4 = 32768,
Key5 = 65536,
Key6 = 131072,
Key7 = 262144,
Key8 = 524288,
FadeIn = 1048576,
Random = 2097152,
Cinema = 4194304,
Target = 8388608,
Key9 = 16777216,
KeyCoop = 33554432,
Key1 = 67108864,
Key3 = 134217728,
Key2 = 268435456,
ScoreV2 = 536870912,
LastMod = 1073741824,
}
As you can see, the list is pretty big, so I can't just try each mods combinations in if() condition.
I would do something like this....
<?php
$user_options = 88;
$no_options = array ( 'None' => 0 );
$game_options = array (
'NoFail' => 1,
'Easy' => 2,
'TouchDevice'=> 4,
'Hidden' => 8,
'HardRock' => 16,
'SuddenDeath' => 32,
'DoubleTime' => 64,
'Relax' => 128,
'HalfTime' => 256,
'Nightcore' => 512,
'Flashlight' => 1024,
'Autoplay' => 2048,
'SpunOut' => 4096,
'Relax2' => 8192,
'Perfect' => 16384,
'Key4' => 32768,
'Key5' => 65536,
'Key6' => 131072,
'Key7' => 262144,
'Key8' => 524288,
'FadeIn' => 1048576,
'Random' => 2097152,
'Cinema' => 4194304,
'Target' => 8388608,
'Key9' => 16777216,
'KeyCoop' => 33554432,
'Key1' => 67108864,
'Key3' => 134217728,
'Key2' => 268435456,
'ScoreV2' => 536870912,
'LastMod' => 1073741824
);
$filtered = array_filter ( $game_options, function ( $value ) use ( $user_options )
{
return ( $value & $user_options ) == $value ? $value : NULL;
});
if ( empty ( $filtered ) )
{
print_r ( $no_options );
}
else
{
print_r ( $filtered );
}
?>
I was thinking, it would be best to only cycle through the user(s) set options, that way you don't have to cycle through all the game_options when maybe only a few lower numbered bits are set...
<?php
$user_options = 344;
$game_options = array (
'NoFail' => 1,
'Easy' => 2,
'TouchDevice'=> 4,
'Hidden' => 8,
'HardRock' => 16,
'SuddenDeath' => 32,
'DoubleTime' => 64,
'Relax' => 128,
'HalfTime' => 256,
'Nightcore' => 512,
'Flashlight' => 1024,
'Autoplay' => 2048,
'SpunOut' => 4096,
'Relax2' => 8192,
'Perfect' => 16384,
'Key4' => 32768,
'Key5' => 65536,
'Key6' => 131072,
'Key7' => 262144,
'Key8' => 524288,
'FadeIn' => 1048576,
'Random' => 2097152,
'Cinema' => 4194304,
'Target' => 8388608,
'Key9' => 16777216,
'KeyCoop' => 33554432,
'Key1' => 67108864,
'Key3' => 134217728,
'Key2' => 268435456,
'ScoreV2' => 536870912,
'LastMod' => 1073741824
);
function get_options ( $game_options, $user_options )
{
/* if no options are set, return this */
$nil = array ( 'None' => 0 );
/* if option(s) are set, return the array of set option(s) */
$set = array ( );
/* only loop the $game_options up until the max set $user_options */
$stop = $user_options;
foreach ( $game_options AS $on => $ov )
{
if ( $ov > $stop )
{
break;
}
else if ( ( $ov & $user_options ) == $ov )
{
$set[$on] = $ov;
$stop -= $ov;
}
}
return empty ( $set ) ? $nil : $set;
}
print_r ( get_options ( $game_options, $user_options ) );
?>
sorry if I don't ask correctly.
This is part of my table:
In daoExcel.php I have this function:
public function selectInconsistencias(){
$aObjects=array();
$dbconn = new DBconnection();
$db = $dbconn->bdConnection();
$stmt = $db->prepare("SELECT rco_rut,rco_nombre,rco_marc, rco_estado FROM act_relcontrol");
$stmt->execute();
$stmt->setFetchMode(PDO::FETCH_ASSOC);
$result = $stmt->fetchAll();
foreach ($result as $row) {
$fecha = date("d/m/Y", strtotime(str_replace("/","-",$row['rco_marc']), mktime(0, 0, 0)));
$aTransfer = new DaoTransferExcel();
$aTransfer->setRut($row['rco_rut']);
$aTransfer->setNombre($row['rco_nombre']);
$aTransfer->setFecha($fecha);
$aTransfer->setEstado($row['rco_estado']);
$aObjects[]=$aTransfer;
}
return $aObjects;
}
Then I return the results to controllerExcel.pho and I use the data in this function:
private function setDatosInconsistencias($datos){
foreach($datos as $sKey=>$oValue){
$list[] = array('rut' => $oValue->getRut(),
'nombre' => $oValue->getNombre(),
'fecha' => $oValue->getFecha(),
'estado' => $oValue->getEstado(),
'count_ent' => '0',
'count_sal' => '0'
);
}
print_r($list);
exit();
}
print_r($list);
Prints all the data from data base of this way:
Well, I need this:
Example 1:
I have this:
But I need only this:
Example 2:
I have this:
And I need only this:
Example 3:
I have this:
And I need only this:
So, I need count the 'M/Ent' and 'M/Sal' by day and I don't need [estado].
Some advice of how do this?
Sorry by my english.
You can store your results in an array where you can use "fecha" as an array key.
In your foreach loop you remember the value of "estado" so you know which field to increment and then unset it from the array because you don't need it.
Then you can reference the $result array by "fecha" and increment the "count_sal" or "count_ent"
For example:
$result = array();
$list = array(
22 => array(
"rut" => "16.534.770-6",
"nombre" => "Miguel Pichipillán S",
"fecha" => "02/09/2015",
"estado" => "M/Ent",
"count_ent" => 0,
"count_sal" => 0
),
23 => array(
"rut" => "16.534.770-6",
"nombre" => "Miguel Pichipillán S",
"fecha" => "02/09/2015",
"estado" => "M/Ent",
"count_ent" => 0,
"count_sal" => 0
),
24 => array(
"rut" => "16.534.770-6",
"nombre" => "Miguel Pichipillán S",
"fecha" => "02/09/2015",
"estado" => "M/Ent",
"count_ent" => 0,
"count_sal" => 0
),
25 => array(
"rut" => "16.534.770-6",
"nombre" => "Miguel Pichipillán S",
"fecha" => "02/09/2015",
"estado" => "M/Sal",
"count_ent" => 0,
"count_sal" => 0
),
);
foreach ($list as $key => $value) {
$estado = $value["estado"];
$fecha = $value["fecha"];
unset($value["estado"]);
if (!isset($result[$fecha])) {
$result[$fecha] = $value;
}
if ($estado === "M/Sal") {
$result[$fecha]["count_sal"]++;
}
if ($estado === "M/Ent") {
$result[$fecha]["count_ent"]++;
}
}
var_dump($result);
Will result in:
array (size=1)
'02/09/2015' =>
array (size=5)
'rut' => string '16.534.770-6' (length=12)
'nombre' => string 'Miguel Pichipillán S' (length=21)
'fecha' => string '02/09/2015' (length=10)
'count_ent' => int 3
'count_sal' => int 1
Demo with multiple dates
I have a requirement to allow my end users to input formula much like a spreadsheet. I have an array like this:
$table = array(
1=>array(
"id"=>1,
"Name"=>"Regulating",
"Quantity"=>"[2]Quantity+[3]Value",
"Value"=>"[2]Cost"
),
...)
The first level array key is always the same value as the id key in that array.
A tabulated example follows:
id Name Quantity Value
1 Regulating [2]Quantity+[3]Value [2]Cost
2 Kerbs 3 6
3 Bricks 9 7
4 Sausages [3]Cost 3
5 Bamboo [4]Quantity [7]Cost
6 Clams [4]Quantity NULL
7 Hardcore [3]Quantity*0.5 12
8 Beetles [6]Quantity*[4]Value [2]Value
The Quantity and Value keys represent formula which reference the [id] and either Quantity, Value or Cost.
Cost is derived by multiplying the Value and Quantity.
I am using:
preg_match_all("/\[(.*?)\]([A-Z]*[a-z]*)/", $string, $matches, PREG_SET_ORDER);
which outputs an array like so for[1][Quantity]:
Array
(
[0] => Array
(
[0] => [2]Quantity
[1] => 2
[2] => Quantity
)
[1] => Array
(
[0] => [3]Value
[1] => 3
[2] => Value
)
)
Iterating through the table using something similar to:
$calcString = $table[1]['Quantity'];`
foreach ($matches as $match) {
$calcString = str_replace($match[0], $table[$match[1]][$match[2]], $calcString);
}
I can get the string to be calculated and am using a matheval class to do the sum.
For example
[1]Quantity = [2]Quantity + [3]Value
[2]Quantity = 3
[3]Value = 7 // [1]Quantity = 3 + 7 = 10
[1]Value = [2]Cost
[2]Cost = [2]Quantity * [2]Value // 3 * 6 = 18
Basically the variables in the table refer to other [id]key in the same table.
But here is my issue
I need to resolve references to other parts of the table (which may or may not themselves be formula) to fill in the blanks. This is outside my comfort zone and I would appreciate any advice (or even better functional code) which provides enlightenment on how I might be able to achieve this.
Thanks
Deep down, you already know how to solve this, you're just intimidated by the task.
A recursive approach would be to expand references instantly. For example,
expand('[1]Value') # returns '[2]Cost'
expand('[2]Cost') # returns '[2]Quantity * [2]Value'
expand('[2]Quantity') # returns 3
expand('[2]Value') # returns 6
eval('3 * 6')
# returns 18
# returns 18
# returns 18
An iterative (non-recursive) approach is to expand one reference at a time and repeat until there are unresolved references in the string.
expand('[1]Value') // returns '[2]Cost'
expand('[2]Cost') // returns '[2]Quantity + [2]Value'
expand('[2]Quantity + [2]Value') // returns 3 for [2]Quantity
expand('3 * [2]Value') // returns 6 for [2]Value
eval('3 * 6')
# returns 18
Normally, I prefer iterative solutions, because they're much less prone to stack overflows. However, recursive solutions are usually easier to write.
Here's a quickly slapped-together recursive evaluator: https://gist.github.com/stulentsev/b270bce4be67bc1a96ae (written in ruby, though)
If calcString's are reasonably sized and you don't expect replacements to get too elaborate, you could use a while loop to simulate the recursion. Here's an example that outputs the string along the way as it is being modified:
$calcString = $table[8]['Quantity'];
preg_match_all("/\[(.*?)\]([A-Z]*[a-z]*)/", $calcString, $matches, PREG_SET_ORDER);
print_r($calcString . "\n");
while (!empty($matches)){
foreach ($matches as $match) {
preg_match_all("/\[(.*?)\](Cost)/", $match[0], $matchCost, PREG_SET_ORDER);
if (!empty($matchCost)){
$cost = $table[$matchCost[0][1]]['Quantity'] . "*" . $table[$matchCost[0][1]]['Value'];
$calcString = str_replace($match[0], $cost, $calcString);
} else {
$calcString = str_replace($match[0], $table[$match[1]][$match[2]], $calcString);
}
print_r($calcString . "\n");
}
preg_match_all("/\[(.*?)\]([A-Z]*[a-z]*)/", $calcString, $matches, PREG_SET_ORDER);
}
Output:
[6]Quantity*[4]Value
[4]Quantity*[4]Value
[4]Quantity*3
[3]Cost*3
9*7*3
The table variable:
$table = array(
1 => array(
"id" => 1,
"Name" => "Regulating",
"Quantity" => "[2]Quantity+[3]Value",
"Value" => "[2]Cost"
),
2 => array(
"id" => 2,
"Name" => "Kerbs",
"Quantity" => 3,
"Value" => 6
),
3 => array(
"id" => 3,
"Name"=>"Bricks",
"Quantity"=> 9,
"Value"=> 7
),
4 => array(
"id" => 2,
"Name" => "Sausages",
"Quantity" => "[3]Cost",
"Value" => 3
),
5 => array(
"id" => 2,
"Name" => "Bamboo",
"Quantity" => "[4]Quantity",
"Value" => "[7]Cost"
),
6 => array(
"id" => 2,
"Name" => "Clams",
"Quantity" => "[4]Quantity",
"Value" => NULL
),
7 => array(
"id" => 2,
"Name" => "Hardcore",
"Quantity" => "[3]Quantity*0.5",
"Value" => 12
),
8 => array(
"id" => 2,
"Name" => "Beetles",
"Quantity" => "[6]Quantity*[4]Value",
"Value" => "[2]Value"
)
);
A dangerously easy, and your-situation-specific well-performable solution!
<?php
class solver {
private
// The final output array
$arr_evaled,
// When a cell gains its final value, the corresponding entry in the following array gets marked as being done!
$arr_done;
private $solving_iterations_count;
public function solver($array) {
$this->arr_done = array();
foreach($array as $k => $arr)
$this->arr_done[$k] = array('Quantity' => false, 'Value' => false);
// Firstly,expand all of the "[x]Cost"s to "([x]Quantity*[x]Value)"s!
$this->arr_evaled = array_map(
function($v){ return preg_replace('#\[(\d*?)\]Cost#', '([$1]Quantity*[$1]Value)', $v); },
$array
);
$this->solving_iterations_count = 0;
$this->solve();
}
private function isDone() {
foreach($this->arr_done as $a)
if($a['Quantity'] == false || $a['Value'] == false)
return false;
return true;
}
private function isCellDone($id, $fieldName) {
return $this->arr_done[$id][$fieldName];
}
private function markCellAsDone($id, $fieldName, $evaluation) {
$this->arr_done[$id][$fieldName] = true;
$this->arr_evaled[$id][$fieldName] = $evaluation;
}
private function isEvaluable($str) {
return preg_match('#^[0-9*+-\/\(\)\.]*$#', $str) == 1 || strtolower($str)=='null';
}
private function replace($from, $to) {
foreach($this->arr_evaled as &$arr) {
$arr['Quantity'] = str_replace($from, $to, $arr['Quantity']);
$arr['Value'] = str_replace($from, $to, $arr['Value']);
}
}
private function solve() {
$isSolvable = true; // YOUR TODO: I believe coding this part is also fun!) (e.g: check for "reference cycles")
if(!$isSolvable) return null;
while( !$this->isDone() )
{
foreach($this->arr_evaled as $arr) {
foreach(['Quantity', 'Value'] as $fieldName) {
if(!$this->isCellDone($arr['id'], $fieldName)) {
if($this->isEvaluable($arr[$fieldName])) {
$evaluation = eval("return {$arr[$fieldName]};");
$this->markCellAsDone($arr['id'], $fieldName, $evaluation);
$this->replace("[{$arr['id']}]$fieldName", "$evaluation");
}
}
}
}
$this->solving_iterations_count++;
}
foreach($this->arr_evaled as &$row)
$row['Cost'] = $row['Quantity'] * $row['Value'];
return $this->arr_evaled;
}
public function print_tabulated() {
echo "The count of solving iterations: {$this->solving_iterations_count}<br/><br/>";
echo '<table border="1"><tr><th>id</th><th>Name</th><th>Quantity</th><th>Value</th><th>Cost</th></tr>';
foreach($this->arr_evaled as $arr)
echo "<tr><td>{$arr['id']}</td><td>{$arr['Name']}</td><td>{$arr['Quantity']}</td><td>{$arr['Value']}</td><td>{$arr['Cost']}</td></tr>";
echo '</table>';
}
}
// Testing
$arr = array(
1 => array( 'id' => 1, 'Name' => 'Regulating', 'Quantity' => '[2]Quantity+[3]Value', 'Value' => '[2]Cost' ),
2 => array( 'id' => 2, 'Name' => 'Kerbs', 'Quantity' => '3', 'Value' => '6' ),
3 => array( 'id' => 3, 'Name' => 'Bricks', 'Quantity' => '9', 'Value' => '7' ),
4 => array( 'id' => 4, 'Name' => 'Sausages', 'Quantity' => '[3]Cost', 'Value' => '3' ),
5 => array( 'id' => 5, 'Name' => 'Bamboo', 'Quantity' => '[4]Quantity', 'Value' => '[7]Cost' ),
6 => array( 'id' => 6, 'Name' => 'Clams', 'Quantity' => '[4]Quantity', 'Value' => 'NULL' ),
7 => array( 'id' => 7, 'Name' => 'Hardcore', 'Quantity' => '[3]Quantity*0.5', 'Value' => '12' ),
8 => array( 'id' => 8, 'Name' => 'Beetles', 'Quantity' => '[6]Quantity*[4]Value', 'Value' => '[2]Value' ),
);
echo '<pre>';
(new solver($arr))->print_tabulated();
Here is the output:
I would like to merge two arrays recursively, leaving associative keys in place, but replace other. I tried using is_numeric() for key checking, but keys '10' and '11' are replaced.
Sample arrays:
Array1:
$arr1['assoc']='foobar';
$arr1[]='test index';
$arr1[][]=array(3,4);
$arr1['10']['test10'][]=array(0,1);
$arr1['11']['test11']=45;
$arr1['multiarray'][]=array(0,1);
Array2:
$arr2[]=1;
$arr2[][]=2;
$arr2['assoc']='test passed';
$arr2['10']['test10'][]=array(0,2);
$arr2['11']['test11']=array(4,5);
$arr2['multiarray'][]=array(0,2);
How to merge them to get this (with a general function):
array(
'assoc' => 'test passed',
0 => 'test index',
1 => array(
0 => array(
0 => 3,
1 => 4,
),
),
10 => array(
'test10' => array (
0 => array(
0 => 0,
1 => 1,
),
1 => array(
0 => 0,
1 => 2,
),
),
),
11 => array(
'test11' => array (
1 => 4,
2 => 5,
),
),
'multiarray' => array(
0 => array(
0 => 0,
1 => 1,
),
1 => array(
0 => 0,
0 => 2,
),
),
2 => 1,
3 => array(
0 => 2,
),
)
Preserving keys' order is not important.
[Edit] Solution:
function array_max_index_key($arr) {
$prev = -1;
if(is_array($arr)) {
$keys = array_keys($arr);
foreach($keys as $k => $key) {
if(is_numeric($key)) {
if($key == $prev+1) {
$prev=$key;
} else break;
}
}
}
return $prev;
}
function justfortesting($a1, $a2) {
$res=$a1;
$max_key=array_max_index_key($res);
if(is_array($a1)) {
foreach ($a2 as $k => $v) {
if(is_numeric($k) && $k<=$max_key) {
$max_key++;
$res[$max_key]=$v;
} elseif (is_array($v)) {
$res[$k]=justfortesting($a1[$k], $v);
} else {
$res[$k]=$v;
}
}
} else {
$res=$a2;
}
return $res;
}
$arr3=justfortesting($arr1, $arr2);
Check for is_string() instead of is_numeric()
Edited:
when you ask for
is_numeric($key)
check for
is_numeric($key) and !is_string($key)
I have the following 2D array and I would like to compare some values. First I would like to get the highest value from the array and depends on time extract from the previous value with the same index.
example: highest(work_something(223))-previous(work_something(120))
$data = array(
0 => array(
'time' => '2011-10-03 18:43:00',
),
1 => array(
'time' => '2011-10-03 18:44:00',
),
2 => array(
'time' => '2011-10-03 18:45:00',
'item_something' => -17,
'keyword_something' => 0,
'keyword_something_1' => 0,
'search_something' => 0,
'search_links_something' => 0,
'work_something' => 120,
),
3 => array(
'time' => '2011-10-03 18:45:00',
'item_something' => -17,
'keyword_something' => 0,
'keyword_something_1' => 0,
'search_something' => 0,
'search_links_something' => 0,
'work_something' => 223,
),
);
$array //This is your 2D array
$highest = 0;
foreach($array as $key => $value):
if(isset($value['work_something'])){
if($value['work_something'] > $highest){
$highest = $value['work_something']; //This is highest 'work_something' value
$highest_array_key = $key; //This is the key of 'work_something' array
}
}
endforeach;
//To compare with previews element use
$array[$highest_array_key - 1] //this is prew element
example: highest(work_something(223))-previous(work_something(120))
$highest - $array[$highest_array_key - 1]['work_something'];