I have a database with some questions and I want every time the page is opened, not refreshed to show them in different order.
The shuffling, it's ok :
function shuffle_keys( &$array ) {
$keys = array_keys($array);
shuffle($keys);
foreach($keys as $key) {
$new[$key] = $array[$key];
}
$array = $new;
}
Shuffle the array with values from database and printing it:
shuffle_keys($array_questions);
foreach( $array_questions as $key => $val ) {
$key_value = ++$key;
echo "<a href = '?id=$val'>".$key_value."</a> ";
}
Just now, when I refresh every time the shuffling is different I want it this way only when I first open the page.
If you want to have the same shuffling for the same session, (that's what I understood)
You can use a $_SESSION variable to store your array.
session_start();
if (isset($_SESSION['array_questions']))
$array_questions=$_SESSION['array_questions'];
else
{
shuffle_keys($array_questions);
foreach( $array_questions as $key => $val ) {
$key_value = ++$key;
echo "<a href = '?id=$val'>".$key_value."</a> ";
}
$_SESSION['array_questions']=$array_questions;
}
You cannot detect a page refresh on its own. Perhaps consider setting a cookie and asserting whether it exists on page open?
You can use a static variable for the purpose. Just create a class as below:
class Base {
protected static $variable = 0;
}
class child extends Base {
function set() {
self::$variable = 1; // let say 1 = 'sorted'
}
function show() {
echo(self::$variable);
}
}
Now when you enter your site,
Create an object and set the variable, calling the method
$c1 = new Child();
if($c1->show() == 0)
{
// sort your array here and set the static flag to sorted(1)
$c1->set();
}
Hope this help...
Related
I'm running a foreach loop for the whole script that checks 9 things.
Let's say five of them have value "a" and four of them have value "b".
How do I write an IF condition (or something) that only returns "a" and "b" once?
Simple method (check last value)
Use a variable which stores the previous contents, and compare it with the current iteration (only works if the similar items are sequential)
$last_thing = NULL;
foreach ($things as $thing) {
// Only do it if the current thing is not the same as the last thing...
if ($thing != $last_thing) {
// do the thing
}
// Store the current thing for the next loop
$last_thing = $thing;
}
More robust method (store used values on an array)
Or, if you have complex objects, where you need to check an inner property and the like things are not sequential, store the ones used onto an array:
$used = array();
foreach ($things as $thing) {
// Check if it has already been used (exists in the $used array)
if (!in_array($thing, $used)) {
// do the thing
// and add it to the $used array
$used[] = $thing;
}
}
For example (1):
// Like objects are non-sequential
$things = array('a','a','a','b','b');
$last_thing = NULL;
foreach ($things as $thing) {
if ($thing != $last_thing) {
echo $thing . "\n";
}
$last_thing = $thing;
}
// Outputs
a
b
For example (2)
$things = array('a','b','b','b','a');
$used = array();
foreach ($things as $thing) {
if (!in_array($thing, $used)) {
echo $thing . "\n";
$used[] = $thing;
}
}
// Outputs
a
b
Could you be more concrete (it might be helpful to insert a code-snippet with your "content"-objects).
It sounds like, you are trying to get unique values of an array:
$values = array(1,2,2,2,2,4,6,8);
print_r(array_unique($values));
>> array(1,2,4,6,8)
1. PHP function.
I've created validating function, here it is in shorter version:
function my_function($input) {
$settings = my_source(); // function taht outputs a long array
foreach ($settings as $setting) {
$id = $setting['id'];
$foo = $setting['foo'];
$option = get_option('my_theme_settings');
if($foo == "bar") {
$valid_input[$id] = $input[$id];
}
}
return $valid_input;
};
Basically it takes $input and saves it as $valid_input. When it gets new $input it overwrites the old #valid_inpu and so on.
I want to create an additional $valid_input[$id] array that will not overwrite itself, but just push new elements inside.
2. Array_push() that doesn't work.
So the new updated code will look like that:
function my_function($input) {
$settings = my_source(); // function taht outputs a long array
foreach ($settings as $setting) {
$id = $setting['id'];
$foo = $setting['foo'];
$option = get_option('my_theme_settings');
if($foo == "bar") {
$valid_input[$id] = $input[$id];
}
else if($foo == "noupdate") { // it doesn't work
$valid_input[$id] = array();
array_push($valid_input[$id], $input[$id]);
}
}
return $valid_input;
};
As mentioned in comment above - this doesn't work, input always overwrites the option, it creates an array but it always contains only one element that is being erased with the new one (I guess array_push should prevent that behavior, right?).
3. The same happens with $array[] =
function my_function($input) {
$settings = my_source(); // function taht outputs a long array
foreach ($settings as $setting) {
$id = $setting['id'];
$foo = $setting['foo'];
$option = get_option('my_theme_settings');
if($foo == "bar") {
$valid_input[$id] = $input[$id];
}
else if($foo == "noupdate") { // it doesn't work
$valid_input[$id][] = $input[$id];
}
}
return $valid_input;
};
Still it overwrites the old value of $valid_input instead of pushing an element.
Any ideas? Maybe there's something wrong with the code? This whole function a Wordpress callback for function called register_setting(), but I guess it's mostly PHP related as folks on WPSE can't help me.
4. EDIT
This does exactly what I want, but why point 3. doesn't work then?
else if($foo == "noupdate") { // it doesn't work
$valid_input[$id][] = 'something';
$valid_input[$id][] = 'something_else';
$valid_input[$id][] = 'something_else2';
}
$valid_input[$id] needs to be set to array before you treat it as one.
$valid_input[$id] = array();
array_push( $valid_input[$id], "some stuff");
Same deal with [] notation
$valid_input[$id] = array();
$valid_input[$id][] = "some stuff";
To check if the array has been declared, so this:
if(!is_array($valid_input[$id]){
$valid_input[$id] = array();
}
The thing is that objects are passed as reference. you need to clone the objects before using the array_push function. here is a sample function that will clone an object:
function DeepCopy($ObjectToCopy) {
return unserialize(serialize($ObjectToCopy));
}
then you can use it this way
array_push($MyObjectsArray, DeepCopy($MyObject));
is it possible that you are trying to push a new value to the array with a key value that already exists? i would test for an existing key value in your array before trying to push a value/key pair to it. example:
if ( !isset( $arr[ $key ] ) ) {
$arr[ $key ] = $value;
} else {
echo " duplicate key value ";
}
Either array_push() or a variable used with the array append operator [] need to actually be an array or these won't work. Double check that whatever is in $valid_input[$id] is an array before doing array operations on the variable. Check by doing:
if (is_array($valid_input[$id])) {
// your code
}
Hi I have a PHP array with a variable number of keys (keys are 0,1,2,3,4.. etc)
I want to process the first value differently, and then the rest of the values the same.
What's the best way to do this?
$first = array_shift($array);
// do something with $first
foreach ($array as $key => $value) {
// do something with $key and $value
}
I would do this:
$firstDone = FALSE;
foreach ($array as $value) {
if (!$firstDone) {
// Process first value here
$firstDone = TRUE;
} else {
// Process other values here
}
}
...but whether that is the best way is debatable. I would use foreach over any other method, because then it does not matter what the keys are.
Here is one way:
$first = true;
foreach($array as $key => $value) {
if ($first) {
// something different
$first = false;
}
else {
// regular logic
}
}
$i = 0;
foreach($ur_array as $key => $val) {
if($i == 0) {
//first index
}
else {
//do something else
}
$i++;
}
I would do it like this if you're sure the array contains at least one entry:
processFirst($myArray[0]);
for ($i=1; $i<count($myArray); $1++)
{
processRest($myArray[$i]);
}
Otherwise you'll need to test this before processing the first element
I've made you a function!
function arrayCallback(&$array) {
$callbacks = func_get_args(); // get all arguments
array_shift($callbacks); // remove first element, we only want the callbacks
$callbackindex = 0;
foreach($array as $value) {
// call callback
$callbacks[$callbackindex]($value);
// make sure it keeps using last callback in case the array is bigger than the amount of callbacks
if(count($callbacks) > $callbackindex + 1) {
$callbackindex++;
}
}
}
If you call this function, it accepts an array and infinite callback arguments. When the array is bigger than the amount of supplied functions, it stays at the last function.
You can simply call it like this:
arrayCallback($array, function($value) {
print 'callback one: ' . $value;
}, function($value) {
print 'callback two: ' . $value;
});
EDIT
If you wish to avoid using a function like this, feel free to pick any of the other correct answers. It's just what you prefer really. If you're repeatedly are planning to loop through one or multiple arrays with different callbacks I suggest to use a function to re-use code. (I'm an optimisation freak)
In php I am converting posted data from a form to objects like this:
<?php
...some code...
$post = new stdClass;
foreach ($_POST as $key => $val)
$post->$key = trim(strip_tags($_POST[$key]));
?>
Then in my page I just echo posted data like this :
<?php echo $post->Name; ?>
<?php echo $post->Address; ?>
etc...
This works fine but I have multiple checkboxes that are part of a group and I echo the results of that, like this:
<?php
$colors = $_POST['color_type'];
if(empty($colors))
{
echo("No color Type Selected.");
}
else
{
$N = count($colors);
for($i=0; $i < $N; $i++)
{
echo($colors[$i] . ", ");
}
}
?>
That works when I am just using array, but how do I write this as object syntax?
using your code
function array_to_object($arr) {
$post = new stdClass;
foreach ($arr as $key => $val) {
if(is_array($val)) {
$post->$key = post_object($val);
}else{
$post->$key = trim(strip_tags($arr[$key]));
}
}
return $post;
}
$post = array_to_object($_POST);
or more complex solution
function arrayToObject($array) {
if(!is_array($array)) {
return $array;
}
$object = new stdClass();
if (is_array($array) && count($array) > 0) {
foreach ($array as $name=>$value) {
$name = strtolower(trim($name));
if (!empty($name)) {
$object->$name = arrayToObject($value);
}
}
return $object;
}
else {
return FALSE;
}
}
from http://www.richardcastera.com/blog/php-convert-array-to-object-with-stdclass
why would you want that? What's wrong with an array?
Use Object Oriented Programming, which might be what you are looking for. Treat it as an object, by making a class called Color and doing $colors[$i] = new Color();
This way you can do whatever you want with it, and add functions to it.
Pretty simple -- when you attach the color_type key to your object, it'll become an array that's a property of your object. This is most likely what you want: you probably won't want to turn that array into its own stdClass-based object, because then you won't be able to iterate through all the values (as easily). Here's a snippet:
<?php
// putting in both of these checks prevents you from throwing an E_WARNING
// for a non-existent property. E_WARNINGs aren't dangerous, but it makes
// your error messages cleaner when you don't have to wade through a bunch
// of E_WARNINGS.
if (!isset($post->color_type) || empty($post->color_type)) {
echo 'No colour type selected.'; // apologies for the Canadian spelling!
} else {
// this loop does exactly the same thing as your loop, but it makes it a
// bit more succinct -- you don't have to store the count of array values
// in $N. Bit of syntax that speeds things up!
foreach ($post->color_type as $thisColor) {
echo $thisColor;
}
}
?>
Hope this helps! Of course, in a real-life setting, you'll want to do all sorts of data validation and cleaning -- for instance, you'll want to check that the browser actually passed an array of values for $_POST['color_type'], and you'll want to clean the output in case someone is trying to inject an exploit into your page (by going echo htmlspecialchars($thisColor); -- this turns all characters like < and > into HTML entities so they can't insert JavaScript code).
I have some logic that is being used to sort data but depending on the user input the data is grouped differently. Right now I have five different functions that contain the same logic but different groupings. Is there a way to combine these functions and dynamically set a value that will group properly. Within the function these assignments are happening
For example, sometimes I store the calculations simply by:
$calcs[$meter['UnitType']['name']] = ...
but other times need a more specific grouping:
$calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] =...
As you can see sometimes it is stored in a multidiminesional array and other times not. I have been trying to use eval() but without success (not sure that is the correct approach). Storing the data in a temporary variable does not really save much because there are many nested loops and if statements so the array would have to be repeated in multiple places.
EDIT
I hope the following example explains my problem better. It is obviously a dumbed down version:
if(){
$calcs[$meter['UnitType']['name']] = $data;
} else {
while () {
$calcs[$meter['UnitType']['name']] = $data;
}
}
Now the same logic can be used but for storing it in different keys:
if(){
$calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data;
} else {
while () {
$calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data;
}
}
Is there a way to abstract out the keys in the $calc[] array so that I can have one function instead of having multiple functions with different array keys?
You can use this if you want to get&set array values dynamically.
function getVal($data,$chain){
$level = $data;
for($i=0;$i<count($chain);$i++){
if(isset($level[$chain[$i]]))
$level = $level[$chain[$i]];
else
return null; // key does not exist, return null
}
return $level;
}
function setVal(&$data,$chain,$value){
$level = &$data;
for($i=0;$i<count($chain);$i++){
$level = &$level[$chain[$i]]; // set reference (&) in order to change the value of the object
}
$level = $value;
}
How it works:
Calling getVal($data,array('foo','bar','2017-08')) will return the equivalent of $data['foo']['bar']['2017-08'].
Calling setVal($data,array('foo','bar','2017-08'),'hello') will set value as if you called
$data['foo']['bar']['2017-08'] = 'hello'. non-existent keys will be created automatically by php magic.
This can be useful if you want to build the structure of the array dynamically.
Here's a function I wrote for setting deeply nested members on arrays or objects:
function dict_set($var, $path, $val) {
if(empty($var))
$var = is_array($var) ? array() : new stdClass();
$parts = explode('.', $path);
$ptr =& $var;
if(is_array($parts))
foreach($parts as $part) {
if('[]' == $part) {
if(is_array($ptr))
$ptr =& $ptr[];
} elseif(is_array($ptr)) {
if(!isset($ptr[$part]))
$ptr[$part] = array();
$ptr =& $ptr[$part];
} elseif(is_object($ptr)) {
if(!isset($ptr->$part))
$ptr->$part = array();
$ptr =& $ptr->$part;
}
}
$ptr = $val;
return $var;
}
Using your example data:
$array = [];
$array = dict_set($array, 'resource1.unit1.2017-10', 'value1');
$array = dict_set($array, 'resource1.unit2.2017-11', 'value2');
$array = dict_set($array, 'resource2.unit1.2017-10', 'value3');
print_r($array);
Results in output like:
Array
(
[resource1] => Array
(
[unit1] => Array
(
[2017-10] => value1
)
[unit2] => Array
(
[2017-11] => value2
)
)
[resource2] => Array
(
[unit1] => Array
(
[2017-10] => value3
)
)
)
The second argument to dict_set() is a $path string in dot-notation. You can build this using dynamic keys with period delimiters between the parts. The function works with arrays and objects.
It can also append incremental members to deeply nested array by using [] as an element of the $path. For instance: parent.child.child.[]
Would it not be easier to do the following
$calcs = array(
$meter['Resource']['name'] => array(
$meter['UnitType']['name'] => 'Some Value',
$meter['UnitType']['name2'] => 'Some Value Again'
),
);
or you can use Objects
$calcs = new stdClass();
$calcs->{$meter['UnitType']['name']} = 'Some Value';
but I would advice you build your structure in arrays and then do!
$calcs = (object)$calcs_array;
or you can loop your first array into a new array!
$new = array();
$d = date('Y-m',$start);
foreach($meter as $key => $value)
{
$new[$key]['name'][$d] = array();
}
Give it ago and see how the array structure comes out.
Try to use a switch case.
<?php
$userinput = $calcs[$meter['UnitType']['name']] = $data;;
switch ($userinput) {
case "useriput1":
while () {
$calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data;
}
break;
case "userinput2":
while () {
$calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data;
}
break;
...
default:
while () {
$calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data;
}
}
?>
I agree with the comment on the OP by #Jake N that perhaps using objects is a better approach. Nonetheless, if you want to use arrays, you can check for the existence of keys in a conditional, like so:
if(
array_key_exists('Resource', $meter)
) {
$calcs[$meter['Resource']['name']][$meter['UnitType']['name']][date('Y-m',$start)] = $data;
} else {
$calcs[$meter['UnitType']['name']] = $data;
}
On the other hand, if you want to use objects, you can create a MeterReading object type, and then add MeterReading instances as array elements to your $calcs array, like so:
// Object defintion
class MeterReading {
private $data;
private $resource;
private $startDate;
private $unitType;
public function __construct(Array $meter, $start, $data) {
$this->unitType = $meter['UnitType']['name'];
$this->resource = $meter['Resource']['name'];
$this->startDate = date('Y-m',$start);
}
public function data() {
return $this->data;
}
public function resource() {
return $this->resource;
}
public function startDate() {
return $this->startDate;
}
public function unitType() {
return $this->unitType;
}
}
// Example population
$calcs[] = new MeterReading($meter, $start, $data);
// Example usage
foreach($calcs as $calc) {
if($calc->resource()) {
echo 'Resource: ' . $calc->resource() . '<br>';
}
echo 'Unit Type: ' . $calc->unitType() . '<br>';
echo 'Start Date: ' . $calc->startDate() . '<br>';
echo 'Data: ' . $calc->data() . '<br>';
}
Obviously you can take this further, such as checking the existence of array keys in the object constructor, giving the object property resource a default value if not provided, and so on, but this is a start to an OO approach.
You can use this library to get or set value in multidimensional array using array of keys:
Arr::getNestedElement($calcs, [
$meter['Resource']['name'],
$meter['UnitType']['name'],
date('Y-m', $start)
]);
to get value or:
Arr::handleNestedElement($calcs, [
$meter['Resource']['name'],
$meter['UnitType']['name'],
date('Y-m', $start)
], $data);
to set $data as value.