Related
I have a foreach loop and I want to see if there is a next element in the loop so I can compare the current element with the next. How can I do this? I've read about the current and next functions but I can't figure out how to use them.
A unique approach would be to reverse the array and then loop. This will work for non-numerically indexed arrays as well:
$items = array(
'one' => 'two',
'two' => 'two',
'three' => 'three'
);
$backwards = array_reverse($items);
$last_item = NULL;
foreach ($backwards as $current_item) {
if ($last_item === $current_item) {
// they match
}
$last_item = $current_item;
}
If you are still interested in using the current and next functions, you could do this:
$items = array('two', 'two', 'three');
$length = count($items);
for($i = 0; $i < $length - 1; ++$i) {
if (current($items) === next($items)) {
// they match
}
}
#2 is probably the best solution. Note, $i < $length - 1; will stop the loop after comparing the last two items in the array. I put this in the loop to be explicit with the example. You should probably just calculate $length = count($items) - 1;
You could probably use while loop instead of foreach:
while ($current = current($array) )
{
$next = next($array);
if (false !== $next && $next == $current)
{
//do something with $current
}
}
If the indexes are continuous:
foreach ($arr as $key => $val) {
if (isset($arr[$key+1])) {
echo $arr[$key+1]; // next element
} else {
// end of array reached
}
}
As php.net/foreach points out:
Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer. Don't rely on the array pointer during or after the foreach without resetting it.
In other words - it's not a very good idea to do what you're asking to do. Perhaps it would be a good idea to talk with someone about why you're trying to do this, see if there's a better solution? Feel free to ask us in ##PHP on irc.freenode.net if you don't have any other resources available.
You could get the keys/values and index
<?php
$a = array(
'key1'=>'value1',
'key2'=>'value2',
'key3'=>'value3',
'key4'=>'value4',
'key5'=>'value5'
);
$keys = array_keys($a);
foreach(array_keys($keys) as $index ){
$current_key = current($keys); // or $current_key = $keys[$index];
$current_value = $a[$current_key]; // or $current_value = $a[$keys[$index]];
$next_key = next($keys);
$next_value = $a[$next_key] ?? null; // for php version >= 7.0
echo "{$index}: current = ({$current_key} => {$current_value}); next = ({$next_key} => {$next_value})\n";
}
result:
0: current = (key1 => value1); next = (key2 => value2)
1: current = (key2 => value2); next = (key3 => value3)
2: current = (key3 => value3); next = (key4 => value4)
3: current = (key4 => value4); next = (key5 => value5)
4: current = (key5 => value5); next = ( => )
if its numerically indexed:
foreach ($foo as $key=>$var){
if($var==$foo[$key+1]){
echo 'current and next var are the same';
}
}
The general solution could be a caching iterator. A properly implemented caching iterator works with any Iterator, and saves memory. PHP SPL has a CachingIterator, but it is very odd, and has very limited functionality. However, you can write your own lookahead iterator like this:
<?php
class NeighborIterator implements Iterator
{
protected $oInnerIterator;
protected $hasPrevious = false;
protected $previous = null;
protected $previousKey = null;
protected $hasCurrent = false;
protected $current = null;
protected $currentKey = null;
protected $hasNext = false;
protected $next = null;
protected $nextKey = null;
public function __construct(Iterator $oInnerIterator)
{
$this->oInnerIterator = $oInnerIterator;
}
public function current()
{
return $this->current;
}
public function key()
{
return $this->currentKey;
}
public function next()
{
if ($this->hasCurrent) {
$this->hasPrevious = true;
$this->previous = $this->current;
$this->previousKey = $this->currentKey;
$this->hasCurrent = $this->hasNext;
$this->current = $this->next;
$this->currentKey = $this->nextKey;
if ($this->hasNext) {
$this->oInnerIterator->next();
$this->hasNext = $this->oInnerIterator->valid();
if ($this->hasNext) {
$this->next = $this->oInnerIterator->current();
$this->nextKey = $this->oInnerIterator->key();
} else {
$this->next = null;
$this->nextKey = null;
}
}
}
}
public function rewind()
{
$this->hasPrevious = false;
$this->previous = null;
$this->previousKey = null;
$this->oInnerIterator->rewind();
$this->hasCurrent = $this->oInnerIterator->valid();
if ($this->hasCurrent) {
$this->current = $this->oInnerIterator->current();
$this->currentKey = $this->oInnerIterator->key();
$this->oInnerIterator->next();
$this->hasNext = $this->oInnerIterator->valid();
if ($this->hasNext) {
$this->next = $this->oInnerIterator->current();
$this->nextKey = $this->oInnerIterator->key();
} else {
$this->next = null;
$this->nextKey = null;
}
} else {
$this->current = null;
$this->currentKey = null;
$this->hasNext = false;
$this->next = null;
$this->nextKey = null;
}
}
public function valid()
{
return $this->hasCurrent;
}
public function hasNext()
{
return $this->hasNext;
}
public function getNext()
{
return $this->next;
}
public function getNextKey()
{
return $this->nextKey;
}
public function hasPrevious()
{
return $this->hasPrevious;
}
public function getPrevious()
{
return $this->previous;
}
public function getPreviousKey()
{
return $this->previousKey;
}
}
header("Content-type: text/plain; charset=utf-8");
$arr = [
"a" => "alma",
"b" => "banan",
"c" => "cseresznye",
"d" => "dio",
"e" => "eper",
];
$oNeighborIterator = new NeighborIterator(new ArrayIterator($arr));
foreach ($oNeighborIterator as $key => $value) {
// you can get previous and next values:
if (!$oNeighborIterator->hasPrevious()) {
echo "{FIRST}\n";
}
echo $oNeighborIterator->getPreviousKey() . " => " . $oNeighborIterator->getPrevious() . " -----> ";
echo "[ " . $key . " => " . $value . " ] -----> ";
echo $oNeighborIterator->getNextKey() . " => " . $oNeighborIterator->getNext() . "\n";
if (!$oNeighborIterator->hasNext()) {
echo "{LAST}\n";
}
}
You could get the keys of the array before the foreach, then use a counter to check the next element, something like:
//$arr is the array you wish to cycle through
$keys = array_keys($arr);
$num_keys = count($keys);
$i = 1;
foreach ($arr as $a)
{
if ($i < $num_keys && $arr[$keys[$i]] == $a)
{
// we have a match
}
$i++;
}
This will work for both simple arrays, such as array(1,2,3), and keyed arrays such as array('first'=>1, 'second'=>2, 'thrid'=>3).
A foreach loop in php will iterate over a copy of the original array, making next() and prev() functions useless. If you have an associative array and need to fetch the next item, you could iterate over the array keys instead:
foreach (array_keys($items) as $index => $key) {
// first, get current item
$item = $items[$key];
// now get next item in array
$next = $items[array_keys($items)[$index + 1]];
}
Since the resulting array of keys has a continuous index itself, you can use that instead to access the original array.
Be aware that $next will be null for the last iteration, since there is no next item after the last. Accessing non existent array keys will throw a php notice. To avoid that, either:
Check for the last iteration before assigning values to $next
Check if the key with index + 1 exists with array_key_exists()
Using method 2 the complete foreach could look like this:
foreach (array_keys($items) as $index => $key) {
// first, get current item
$item = $items[$key];
// now get next item in array
$next = null;
if (array_key_exists($index + 1, array_keys($items))) {
$next = $items[array_keys($items)[$index + 1]];
}
}
$next_data = $data;
$prev_key = null;
$prev_value = null;
foreach($data as $key => $value)
{
array_shift($next_data);
$next_key = key($next_data);
$next_value = $next_data[$next_key] ?? null;
// Do something here...
$prev_key = $key;
$prev_value = $value;
}
or if the array is associative then you could use current() similar to Andrei Krasutski's solution and key()
$values = [];
array_push($values, ["XYZ"=>100]);
array_push($values, ["ABC"=>10]);
array_push($values, ["XYZ"=>130]);
array_push($values, ["DEF"=>4]);
array_push($values, ["XYZ"=>5]);
$count = count($values);
foreach ($values as $index => $currentValue) {
if ($index < $count - 1) {
$nextValue = $values[$index + 1];
echo key($currentValue) . "=" . current($currentValue) . " followed by " . key($nextValue) . "/" . current($nextValue) . "<br>\n";
} else {
echo key($currentValue) . "=" . current($currentValue);
}
}
See https://onlinephp.io/c/dc58d for a running example.
or if the array is using named pairs:
$values = [];
array_push($values, ["type"=>"XYZ", "value"=>100]);
array_push($values, ["type"=>"ABC", "value"=>10]);
array_push($values, ["type"=>"XYZ", "value"=>130]);
array_push($values, ["type"=>"DEF", "value"=>"Lorem"]);
array_push($values, ["type"=>"XYZ", "value"=>5]);
$count = count($values);
foreach ($values as $index => $currentValue) {
if ($index < $count - 1) {
$nextValue = $values[$index + 1];
echo $currentValue['type'] . "=" . $currentValue['value']
. " followed by " . $nextValue['type'] . "/" . $nextValue['value'] . "<br>\n";
} else {
echo $currentValue['type'] . "=" . $currentValue['value'];
}
}
I have an array:
$arr1 = [1,2,2,3,3,3];
Is there any method by which I can delete a duplicate value once like,
some_function($arr1,3);
which gives me the ouput $arr1 = [1,2,2,3,3]
As per the comment, check if there are more than one of the element you're searching for, then find and remove one of them.
function remove_one_duplicate( $arr, $target ) {
if( count( array_keys( $arr, $target ) ) > 1 ) {
unset( $arr[array_search( $target, $arr )] );
}
return $arr;
}
This should work...
function removeduplicate($myarray,$needle) {
if (($nmatches = count($matches = array_keys($myarray,$needle))) >= 2) {
for ($i=0; $i<$nmatches; $i++) {
if ($matches[$i+1] == (1+$matches[$i])) {
array_splice($myarray,$matches[$i],1);
break;
}
}
}
return $myarray;
}
To use the function...
$arr1 = [1,2,2,3,3,3,4,7,3,3];
$newarray = removeduplicate($arr1,3)
print_r($newarray);
EDITED:
If you want the function to modify your original array directly, you can do it (the function will return true if a character has been removed or false if not)...
function removeduplicate(&$myarray,$needle) {
if (($nmatches = count($matches = array_keys($myarray,$needle))) >= 2) {
for ($i=0; $i<$nmatches; $i++) {
if ($matches[$i+1] == (1+$matches[$i])) {
array_splice($myarray,$matches[$i],1);
return true;
}
}
}
return false;
}
So, now you can do...
$arr1 = [1,2,2,2,2,2,3,3,3,4,2,2];
removeduplicate($arr1,2);
print_r($arr1);
This function will copy the array skipping only the second instance of the specified element.
function removeOnce($array, $elem) {
$found = 0;
$result = [];
foreach ($array as $x) {
if ($x == $elem && (++$found) == 2) {
continue;
}
$result[] = $x;
}
return $result;
}
Good day. I have a parcer function that taker an array of string like this:
['str','str2','str2','*str','*str2','**str2','str','str2','str2']
And recursivelly elevates a level those starting with asterix to get this
['str','str2','str2',['str','str2',['str2']],'str','str2','str2']
And the function is:
function recursive_array_parser($ARRAY) {
do {
$i = 0;
$s = null;
$e = null;
$err = false;
foreach ($ARRAY as $item) {
if (!is_array($item)) { //if element is not array
$item = trim($item);
if ($item[0] === '*' && $s == null && $e == null) { //we get it's start and end if it has asterix
$s = $i;
$e = $i;
} elseif ($item[0] === '*' && $e != null)
$e = $i;
elseif (!isset($ARRAY[$i + 1]) || $s != null && $e != null) { //if there are no elements or asterix element ended we elevate it
$e = $e == NULL ? $i : $e;
$head = array_slice($ARRAY, 0, $s);
$_x = [];
$inner = array_slice($ARRAY, $s, $e - $s + 1);
foreach ($inner as $_i)
$_x[] = substr($_i, 1);
$inner = [$_x];
$tail = array_slice($ARRAY, $e + 1, 999) or [];
$X = array_merge($head, $inner);
$ARRAY = array_merge($X, $tail);
$s = null;
$e = null;
$err = true;
}
} else {
$ARRAY[$i] = recursive_array_parser($ARRAY[$i]); //if the item is array of items we recur.
}
$i++;
if ($err == true) {
break 1;
}
}
} while ($err);
return $ARRAY;
}
When this function runs, i get "Fatal error: Maximum function nesting level of '200' reached, aborting!" error.
I know it has something to do with infinite recursion, but i can't track the particular place where it occurs, and this is strange.
I don't normally rewrite code, but your code can be reduced and simplified while, from what I can see, getting the desired result. See if this works for you:
$a = array('a','b','c','*d','*e','**f','g','*h');
print_r($a);
$a = recursive_array_parser($a);
print_r($a);
function recursive_array_parser($array)
{
$ret = array();
for($i=0; $i<sizeof($array); $i++)
{
if($array[$i]{0}!='*') $ret[] = $array[$i];
else
{
$tmp = array();
for($j=$i; $j<sizeof($array) && $array[$j]{0}=='*'; $j++)
{
$tmp[] = substr($array[$j],1);
}
$ret[] = recursive_array_parser($tmp);
$i = $j-1;
}
}
return $ret;
}
Note that it isn't possible for $array[$i] to be an array, so that check is removed. The recursion takes place on the temp array created when a * is found. The $i is closer tied to $array to reset it properly after parsing the series of * elements.
Here's my solution. No nested loops.
function recursive_array_parser($arr) {
$out = array();
$sub = null;
foreach($arr as $item) {
if($item[0] == '*') { // We've hit a special item!
if(!is_array($sub)) { // We're not currently accumulating a sub-array, let's make one!
$sub = array();
}
$sub[] = substr($item, 1); // Add it to the sub-array without the '*'
} else {
if(is_array($sub)) {
// Whoops, we have an active subarray, but this thing didn't start with '*'. End that sub-array
$out[] = recursive_array_parser($sub);
$sub = null;
}
// Take the item
$out[] = $item;
}
}
if(is_array($sub)) { // We ended in an active sub-array. Add it.
$out[] = recursive_array_parser($sub);
$sub = null;
}
return $out;
}
hi i have following array
$langarr[0][0] = gb
$langarr[0][1] = 1
$langarr[1][0] = de
$langarr[1][1] = 2
$langarr[2][0] = fr
$langarr[2][1] = 3
$langarr[3][0] = it
$langarr[3][1] = 5
Now i wanna search to unset like
if(($keyy = array_search('de', $langarr[][0])) !== false) {
unset($langarr[$keyy]);
}
So i wanna search in the langarr[any][0] and if matched I want to delete the whole dataset like unset($langarr[X]);
How can this be achieved?
$langarr = array();
$langarr[0][0] = "gb";
$langarr[0][1] = "1";
$langarr[1][0] = "de";
$langarr[1][1] = "2";
$langarr[2][0] = "fr";
$langarr[2][1] = "3";
$langarr[3][0] = "it";
$langarr[3][1] = "5";
// Get the key of search array
$value = recursive_array_search("de",$langarr);
// print the key
print_r($value);
// unset the array "de" which has key "1"
unset($langarr[$value]);
// print the resultant array
print_r($langarr);
function recursive_array_search($needle,$haystack) {
foreach($haystack as $key=>$value) {
$current_key=$key;
if($needle===$value OR (is_array($value) && recursive_array_search($needle,$value) !== false)) {
return $current_key;
}
}
return false;
}
Use array_filter(). It takes a (anonymous) function as the second argument. The function itself receives an array element as its argument. If that function returns false, the array element is removed from the array.
So to take your example, if $needle is 'de', the subarray is removed.
$langarr = array(
array('gb', 1),
array('de', 2),
);
$needle = 'de';
$langarr = array_filter($langarr, function($row) use($needle) {
return ($row[0] != $needle);
});
Online test
<?php
$langarr[0][0] = "gb";
$langarr[0][1] = 1;
$langarr[1][0] = "de";
$langarr[1][1] = 2;
$langarr[2][0] = "fr";
$langarr[2][1] = 3;
$langarr[4][0] = "it";
$langarr[4][1] = 4;
print_r($langarr);
foreach($langarr as $key=>$data){
if($data[0]=='de'){
unset($langarr[$key]);
}
}
print_r($langarr);
?>
I'm trying to replace the code below
$Palette = array(
"0"=>array("R"=>188,"G"=>224,"B"=>46,"Alpha"=>100),
"1"=>array("R"=>188,"G"=>224,"B"=>46,"Alpha"=>100),
"2"=>array("R"=>188,"G"=>224,"B"=>46,"Alpha"=>100),
"3"=>array("R"=>188,"G"=>224,"B"=>46,"Alpha"=>100),
"4"=>array("R"=>176,"G"=>46,"B"=>224,"Alpha"=>100),
);
with something similar but different values for the R, G and B. I have written the code below so far as a replacement:
$x = '0';
$incrementarray = array("0"=>"A","1"=>"B","2"=>"C","3"=>"D","4"=>"E");
do
{
if ($correct == $incrementarray[$x])
{
$colour[$x] = '"'.$x.'"=>array("R"=>188,"G"=>224,"B"=>46,"Alpha"=>100),';
}
else
{
$colour[$x] = '"'.$x.'"=>array("R"=>255,"G"=>51,"B"=>51,"Alpha"=>100),';
}
$x++;
}
while ($x <= '4');
$allcolours = $colour[0].$colour[1].$colour[2].$colour[3].$colour[4];
however, when I implement it into my script using the line below , it doesn't work.
$Palette = array($allcolours);
$x = '0';
$incrementarray = array("0"=>"A","1"=>"B","2"=>"C","3"=>"D","4"=>"E");
do
{
if ($correct == $incrementarray[$x])
{
$Pallete[$x] = array("R"=>188,"G"=>224,"B"=>46,"Alpha"=>100);
}
else
{
$Pallete[$x] = array("R"=>255,"G"=>51,"B"=>51,"Alpha"=>100);
}
$x++;
}
while ($x <= '4');
there is a little excessive usage of $x.
as a matter of fact, you don't need that variable at all
$Palette = array();
$incrementarray = array("0"=>"A","1"=>"B","2"=>"C","3"=>"D","4"=>"E");
foreach ($incrementarray as $value)
{
if ($correct == $value)
{
$Palette[] = array("R"=>188,"G"=>224,"B"=>46,"Alpha"=>100);
}
else
{
$Palette[] = array("R"=>255,"G"=>51,"B"=>51,"Alpha"=>100);
}
}
you need to create array, not the PHP code to create array.