This question already has answers here:
How to modify an array's values by a foreach loop?
(2 answers)
Closed 4 months ago.
I have this piece of code :
$start = ['23','', 'what'];
foreach($start as $i){
if($i ==''){
$i = 'satisfaction';
}
}
print_r($start);
The output is :
Array
(
[0] => 23
[1] =>
[2] => what
)
Why did index [1] not get replaced with 'satisfaction'. In other words : I don't want to create a new array, but change the index of an existing array. Actually, what I'm trying to achieve is to do intval() on those indexes that are not empty (since intval on an empty index returns 0, which is not what I want).
According to the manual:
In order to be able to directly modify array elements within the loop precede $value with &. In that case the value will be assigned by reference.
So in your case, you should add &:
$start = ['23','', 'what'];
foreach($start as &$i){
// ^ reference
if($i === ''){
$i = 'satisfaction';
}
}
Sidenote: If your intent is to change those numeric values into data type integer, you can use (as you stated) intval or a simple type cast.
$start = ['23','', 'what'];
foreach($start as &$i){
if(is_numeric($i)){
$i = (int) $i;
}
}
var_dump($start);
Because foreach(...) acts "a bit" as a read-only iterator. If you want to modify elements, you'll have to access by reference.
example :
foreach ($start as &$i) {
}
For more info, see doc : http://php.net/manual/fr/control-structures.foreach.php
In your example you are just setting the variable $i, which is just a temporary variable for the loop. Instead, keep the array key in the loop and use that to set the value in the array:
$start = ['23','', 'what'];
foreach($start as $k=>$i){
if($i ==''){
$start[$k] = 'satisfaction';
}
}
Related
Edit1: The problem: I want to convert in php a associative array to a indexed one. So I can return it via json_encode as an array and not as an object. For this I try to fill the missing keys. Here the description:
Got a small problem, I need to transfer a json_encoded array as an array to js. At the moment it returns an Object. I´m working with Angular so I really need an Array. I try to explain it as much as possible.
$arrNew[0][5][0][0][1]["id"] = 1;
//$arrNew[0][0][0][0][1] = "";
//$arrNew[0][1][0][0][1] = "";
//$arrNew[0][2][0][0][1] = "";
//$arrNew[0][3][0][0][1] = "";
//$arrNew[0][4][0][0][1] = "";
$arrNew[0][5][0][0][1]["name"] = 'Test';
var_dump($arrNew);
So if I return it now It returns the second element as object cause of the missing index 0-4 and the 4th element cause of the missing index 0 (associative array -> object)
So if I uncomment the block it works like a charm. Now I have the problem its not every time the element 5 sometime 3, 4 or something else so I build a function which adds them automaticly:
$objSorted = cleanArray($arrNew);
function cleanArray($array){
end($array);
$max = key($array) + 1; //Get the final key as max!
for($i = 0; $i < $max; $i++) {
if(!isset($array[$i])) {
$array[$i] = '';
} else {
end($array[$i]);
$max2 = key($array[$i]) + 1;
for($i2 = 0; $i2 < $max2; $i2++) {
.... same code repeats here for every index
So if I vardump it it returns:
The problem:
On js side its still an object, what I also see is that the elements are not sorted. So I think somehow PHP sees it still as an associative array. Any clue why this happens ? The key is set with the index of the loop and has to be a integer value.
PS: I know reworking it in JS is possible but would have be done nearly on every request with a huge load of loops
If I understand your problem, you create a sparse multidimensional array of objects. Because the arrays have gaps in the keys, json_encode() produces objects on some levels but you need it to produce arrays for all but the most inner level.
The following function fills the missing keys (starting from 0 until the maximum value used as numeric key in an array) on all array levels. It then sorts each array by their keys to make sure json_encode() encodes it as array and not object.
The sorting is needed, otherwise json_encode() generates an object; this behaviour is explained in a note on the json_encode() documentation page:
When encoding an array, if the keys are not a continuous numeric sequence starting from 0, all keys are encoded as strings, and specified explicitly for each key-value pair.
// If $arr has numeric keys (not all keys are tested!) then returns
// an array whose keys are a continuous numeric sequence starting from 0.
// Operate recursively for array values of $arr
function fillKeys(array $arr)
{
// Fill the numeric keys of all values that are arrays
foreach ($arr as $key => $value) {
if (is_array($value)) {
$arr[$key] = fillKeys($value);
}
}
$max = max(array_keys($arr));
// Sloppy detection of numeric keys; it may fail you for mixed type keys!
if (is_int($max)) {
// Fill the missing keys; use NULL as value
$arr = $arr + array_fill(0, $max, NULL);
// Sort by keys to have a continuous sequence
ksort($arr);
}
return $arr;
}
// Some array to test
$arrNew[0][5][0][0][1]["id"] = 1;
$arrNew[0][3][0][2][1]["id"] = 2;
$arrNew[0][5][0][0][1]["name"] = 'Test';
echo("============= Before ==============\n");
echo(json_encode($arrNew)."\n");
$normal = fillKeys($arrNew);
echo("============= After ==============\n");
echo(json_encode($normal)."\n");
The output:
============= Before ==============
[{"5":[[{"1":{"id":1,"name":"Test"}}]],"3":[{"2":{"1":{"id":2}}}]}]
============= After ==============
[[null,null,null,[[null,null,[null,{"id":2}]]],null,[[[null,{"id":1,"name":"Test"}]]]]]
The line $arr = $arr + array_fill(0, $max, NULL); uses NULL as values for the missing keys. This is, I think, the best for the Javascript code that parses the array (you can use if (! arr[0]) to detect the dummy values).
You can use the empty string ('') instead of NULL to get a shorter JSON:
[["","","",[["","",["",{"id":2}]]],"",[[["",{"id":1,"name":"Test"}]]]]]
but it requires slightly longer code on the JS side to detect the dummy values (if (arr[0] != '')).
I have a foreach loop like below code :
foreach($coupons as $k=>$c ){
//...
}
now, I would like to fetch two values in every loop .
for example :
first loop: 0,1
second loop: 2,3
third loop: 4,5
how can I do ?
Split array into chunks of size 2:
$chunks = array_chunk($coupons, 2);
foreach ($chunks as $chunk) {
if (2 == sizeof($chunk)) {
echo $chunk[0] . ',' . $chunk[1];
} else {
// if last chunk contains one element
echo $chunk[0];
}
}
If you want to preserve keys - use third parameter as true:
$chunks = array_chunk($coupons, 2, true);
print_r($chunks);
Why you don't use for loop like this :
$length = count($collection);
for($i = 0; $i < $length ; i+=2)
{
// Do something
}
First, I'm making the assumption you are not using PHP 7.
It is possible to do this however, it is highly, highly discouraged and will likely result in unexpected behavior within the loop. Writing a standard for-loop as suggested by #Rizier123 would be better.
Assuming you really want to do this, here's how:
Within any loop, PHP keeps an internal pointer to the iterable. You can change this pointer.
foreach($coupons as $k=>$c ){
// $k represents the current element
next($coupons); // move the internal array pointer by 1 space
$nextK = current($coupons);
prev($coupons);
}
For more details, look at the docs for the internal array pointer.
Again, as per the docs for foreach (emphasis mine):
Note: In PHP 5, when foreach first starts executing, the internal array pointer is automatically reset to the first element of the
array. This means that you do not need to call reset() before a
foreach loop. As foreach relies on the internal array pointer in PHP
5, changing it within the loop may lead to unexpected behavior. In PHP
7, foreach does not use the internal array pointer.
Let's assume your array is something like $a below:
$a = [
"a"=>1,
"b"=>2,
"c"=>3,
"d"=>4,
"e"=>5,
"f"=>6,
"g"=>7,
"h"=>8,
"i"=>9
];
$b = array_chunk($a,2,true);
foreach ($b as $key=>$value) {
echo implode(',',$value) . '<br>';
}
First we split array into chunks (the parameter true preserves the keys) and then we do a foreach loop. Thanks to the use of implode(), you do not need a conditional statement.
well this'd be 1 way of doing it:
$keys=array_keys($coupons);
for($i=0;$i<count($keys);++$i){
$current=$coupons[$keys[$i]];
$next=(isset($keys[$i+1])?$coupons[$keys[$i+1]]:NULL);
}
now the current value is in $current and the next value is in $next and the current key is in $keys[$i] and the next key is in $keys[$i+1] , and so on.
This question already has answers here:
PHP - Sequence through array and repeat [modulo-operator]
(3 answers)
Closed 9 days ago.
I'm wondering if there is a function built into PHP that I could leverage to loop through an array, and reset to the beginning to continue to loop again.
The use of this would be an array of colors for an SVG that is created with a PHP function. I think my max case would be X but I want to make sure if I have more than X I restart with the color codes.
Below is the code I have that works, but wondering if there is a built in function to do this.
$color_array = array( 1 => '#00cc00', 2=> '#B45F04', 3=> '#0101DF', 4=> '#B40486', 5=> 'F1F105', 6=>'F10505');
$num_color_array = count($color_array); //get number of elements
foreach(loop through array 1){ //psuedo code
$array_color_index = 1;
foreach(loop throguh array 2){ //psuedo code
if($array_color_index > $num_color_array){
$array_color_index = 1; //if > num elements reset
}
$color_fill = $color_array[$array_color_index]; //pull the color code
fill:'.$color_fill.' //use the color code here...simplified for example...
$array_color_index++; //increment index
}
}
You could use something like this (using the modulus):
$color_array = array('#f00', '#0f0', '#00f');
$elements = get_some_colorable_elements();
// For each element in $elements, the modulus returns a value between 0 and the size of $color_array
for ($i = 0; $i < count($elements); $i += 1) {
$colorForElement = $color_array[$i % count($color_array)];
fill_color_for_element($colorForElement);
}
As far as I know there is no built in function specifically for this purpose (other than the modulus).
Try using the modulus:
$color_fill = $color_array[$array_color_index % $num_color_array];
You're getting the remainder of your index divided by the total number of elements.. so when the index = number of elements, remainder = 0, and then it cycles.
If you loop through an array and then start at the beginning again using anything like a foreach() you're essentially creating an infinite loop. I don't think there's a basic function for it, but it's fairly easy to make one. Of course, you'd have to use BREAK to end it.
A function like this would do (it's a Generator, so you need an up to date PHP version)
function constantLoop( $array ) {
while(true) {
foreach( $array as $element ) {
yield $element;
}
}
}
You can use it like this:
foreach( constantLoop( $array ) as $value );
But you HAVE to break, because as the name says, it'll keep looping forever.
This question already has answers here:
php - how to remove all elements of an array after one specified
(3 answers)
Closed 9 years ago.
Is it possible to delete all array elements after an index?
$myArrayInit = array(1=>red, 30=>orange, 25=>velvet, 45=>pink);
now some "magic"
$myArray = delIndex(30, $myArrayInit);
to get
$myArray = array(1=>red, 30=>orange);
due to the keys in $myArray are not successive, I don't see a chance for array_slice()
Please note : Keys have to be preserved! + I do only know the Offset Key!!
Without making use of loops.
<?php
$myArrayInit = [1 => 'red', 30 => 'orange', 25 => 'velvet', 45 => 'pink']; //<-- Your actual array
$offsetKey = 25; //<--- The offset you need to grab
//Lets do the code....
$n = array_keys($myArrayInit); //<---- Grab all the keys of your actual array and put in another array
$count = array_search($offsetKey, $n); //<--- Returns the position of the offset from this array using search
$new_arr = array_slice($myArrayInit, 0, $count + 1, true);//<--- Slice it with the 0 index as start and position+1 as the length parameter.
print_r($new_arr);
Output :
Array
(
[1] => red
[30] => orange
[25] => velvet
)
Try
$arr = array(1=>red, 30=>orange, 25=>velvet, 45=>pink);
$pos = array_search('30', array_keys($arr));
$arr= array_slice($arr,0,$pos+1,true);
echo "<pre>";
print_r($arr);
See demo
I'd iterate over the array up until you reach the key you want to truncate the array thereafter, and add those items to a new - temporary array, then set the existing array to null, then assign the temp array to the existing array.
This uses a flag value to determine your limit:
$myArrayInit = array(1=>'red', 30=>'orange', 25=>'velvet', 45=>'pink');
$new_array = delIndex(30,$myArrayInit);
function delIndex($limit,$array){
$limit_reached=false;
foreach($array as $ind=>$val){
if($limit_reached==true){
unset($array[$ind]);
}
if($ind==$limit){
$limit_reached=true;
}
}
return $array;
}
print_r($new_array);
Try this:
function delIndex($afterIndex, $array){
$flag = false;
foreach($array as $key=>$val){
if($flag == true)
unset($array[$key]);
if($key == $afterIndex)
$flag = true;
}
return $array;
}
This code is not tested
This question already has answers here:
Reference Guide: What does this symbol mean in PHP? (PHP Syntax)
(24 answers)
Closed 9 years ago.
In order to be able to directly modify array elements within the loop precede $value with &. In that case the value will be assigned by reference from http://php.net/manual/en/control-structures.foreach.php.
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
echo $value;
}
$arr = array(1, 2, 3, 4);
foreach ($arr as $value) {
echo $value;
}
In both cases, it outputs 1234. What does adding & to $value actually do?
Any help is appreciated. Thanks!
It denotes that you pass $value by reference. If you change $value within the foreach loop, your array will be modified accordingly.
Without it, it'll passed by value, and whatever modification you do to $value will only apply within the foreach loop.
In the beginning when learning what passing by reference it isn't obvious....
Here's an example that I hope will hope you get a clearer understanding on what the difference on passing by value and passing by reference is...
<?php
$money = array(1, 2, 3, 4); //Example array
moneyMaker($money); //Execute function MoneyMaker and pass $money-array as REFERENCE
//Array $money is now 2,3,4,5 (BECAUSE $money is passed by reference).
eatMyMoney($money); //Execute function eatMyMoney and pass $money-array as a VALUE
//Array $money is NOT AFFECTED (BECAUSE $money is just SENT to the function eatMyMoeny and nothing is returned).
//So array $money is still 2,3,4,5
echo print_r($money,true); //Array ( [0] => 2 [1] => 3 [2] => 4 [3] => 5 )
//$item passed by VALUE
foreach($money as $item) {
$item = 4; //would just set the value 4 to the VARIABLE $item
}
echo print_r($money,true); //Array ( [0] => 2 [1] => 3 [2] => 4 [3] => 5 )
//$item passed by REFERENCE
foreach($money as &$item) {
$item = 4; //Would give $item (current element in array)value 4 (because item is passed by reference in the foreach-loop)
}
echo print_r($money,true); //Array ( [0] => 4 [1] => 4 [2] => 4 [3] => 4 )
function moneyMaker(&$money) {
//$money-array is passed to this function as a reference.
//Any changes to $money-array is affected even outside of this function
foreach ($money as $key=>$item) {
$money[$key]++; //Add each array element in money array with 1
}
}
function eatMyMoney($money) { //NOT passed by reference. ONLY the values of the array is SENT to this function
foreach ($money as $key=>$item) {
$money[$key]--; //Delete 1 from each element in array $money
}
//The $money-array INSIDE of this function returns 1,2,3,4
//Function isn't returing ANYTHING
}
?>
This is reference to a variable and the main use in foreach loop is that you can change the $value variable and that way the array itself would also change.
when you're just referencing values, you won't notice much difference in the case you've posted. the most simple example I can come up with describing the difference of referencing a variable by value versus by reference is this:
$a = 1;
$b = &$a;
$b++;
print $a; // 2
You'll notice $a is now 2 - because $b is a pointer to $a. if you didn't prefix the ampersand, $a would still be 1:
$a = 1;
$b = $a;
$b++;
print $a; // 1
HTH
Normally every function creates a copy of its parameters, works with them, and if you don't return them "deletes them" (when this happens depends on the language).
If run a function with &VARIABLE as parameter that means you added that variable by reference and in fact this function will be able to change that variable even without returning it.