PHP find last occurrence from multidimensional array from given index - php

Is it possible to find the last occurrence of a value in an array element starting at a specific index value. I have found a partial solution in this post [How can I find the key of the last occurrence of an item in a multidimensional array? but it doesn't allow for starting at a specific index. I am looping thru an array matching an 'id' number. If the 'id' number doesn't exist in the current array index, I would like to search back from that point finding the last occurrence of that value.
$last = "";
foreach($arr as $key => $array) {
if ( $array['id'] === $id) {
$last = $key;
}
}
echo $last."\n\n";

If the array has numeric indexes, you can do that with usual for loop
$last = false;
for($i = $start; $i >= 0; $i--) { // $start - index to start look up
if ( $arr[$i]['id'] === $id) {
$last = $i;
break; // if key is found, stop loop
}
}
if($last !== false)
echo $last."\n\n";
else
echo "Not found" . "\n";

<?php
$myArray = [
"bus" => "blue",
"car" => "red",
"shuttle" => "blue",
"bike" => "green";
];
$findValue = "blue";
$startIndex = "bus";
$continue = false;
$lastIndex = null;
foreach ($myArray as $key => $value)
{
if(!$continue && $key === $startIndex)
{
$continue = true;
} else if($continue) {
if($key === $findValue) {
$lastIndex = $key;
}
}
}
Basically what I'm doing here is only checking the index against first index you're trying to find, if its found that index it'll go on to try and compare the current key's value to the one you're trying to specify.

Related

get min and max position in array where value exist

I need to find the min and max position into an array where some value exist!
use a loop inside a loop to compare values is not an option ( my array has 100.000 values )
e.g=
$myarray[0]="red";
$myarray[1]="red";
$myarray[2]="blue";
$myarray[3]="blue";
$myarray[4]="blue";
$myarray[5]="red";
how to get the min and max position where blue exist?
Use the second argument for array_keys:
if($blue = array_keys($myarray, 'blue')) {
$min = min($blue);
$max = max($blue);
}
may be this is the answer?
function getMinKey($arr, $search){
if(!in_array($search, $arr)){
return false;
}
foreach($arr as $key => $value){
if($value == $search){
return $key;
}
}
}
function getMaxKey($arr, $search){
if(!in_array($search, $arr)){
return false;
}
$arrCount = count($arr)-1;
for($i = $arrCount; $i >=0; $i--){
if($arr[$i] == $search){
return $i;
}
}
}
All solutions, so far, have searched the whole array, which might be quite inefficient. You only need to search from the start upto the first "blue" and from the end downto the last "blue". Like this:
$find = "blue";
$first = false;
$last = false;
$max = count($myarray);
$key = 0;
while ($key < $max) {
if ($myarray[$key] == $find) {
$first = $key;
break;
}
$key++;
}
if ($first !== false) {
$key = --$max;
while ($key > 0) {
if ($myarray[$key] == $find) {
$last = $key;
break;
}
$key--;
}
}
Note that this code takes into account that nothing will be found. In that case $first and $last will contain false. It also checks to see if the $first was found to prevent searching through the array twice when there's clearly no need for that.
You can use array_keys with the search_value to extract all the matching keys, and then max and min to get the two ones that you want.
$keys = array_keys($myarray,'blue'); //[2,3,4]
$maxKey = max($keys); //4
$minKey = min($keys); //2
I have to advise that performance wise is better to do a for loop:
$length = count($myarray);
$minKey = FALSE;
$maxKey = FALSE;
$search = 'blue';
for($i=0;$i<$length;$i++){
if($myarray[$i] == $search){
if($minKey === FALSE) $minKey = $i;
$maxKey = $i;
}
}

Find first duplicate in an array

Given an array a that contains only numbers in the range from 1 to a.length, find the first duplicate number for which the second occurrence has the minimal index. In other words, if there are more than 1 duplicated numbers, return the number for which the second occurrence has a smaller index than the second occurrence of the other number does. If there are no such elements, return -1.
My code:
function firstDuplicate($a) {
$unique = array_unique($a);
foreach ($a as $key => $val) {
if ($unique[$key] !== $val){
return $key;
}else{
return -1;
}
}
}
The code above will be OK when the input is [2, 4, 3, 5, 1] but if the input is [2, 1, 3, 5, 3, 2] the output is wrong. The second duplicate occurrence has a smaller index. The expected output should be 3.
How can I fix my code to output the correct result?
$arr = array(2,1,3,5,3,2);
function firstDuplicate($a) {
$res = -1;
for ($i = count($a); $i >= 1; --$i) {
for ($j = 0; $j < $i; ++$j) {
if ($a[$j] === $a[$i]) {
$res = $a[$j];
}
}
}
return $res;
}
var_dump(firstDuplicate($arr));
By traversing the array backwards, you will overwrite any previous duplicates with the new, lower-indexed one.
Note: this returns the value (not index), unless no duplicate is found. In that case, it returns -1.
// Return index of first found duplicate value in array
function firstDuplicate($a) {
$c_array = array_count_values($a);
foreach($c_array as $value=>$times)
{
if($times>1)
{
return array_search($value, $array);
}
}
return -1;
}
array_count_values() will count the duplicate values in the array for you then you just iterate over that until you find the first result with more then 1 and search for the first key in the original array matching that value.
Python3 Solution:
def firstDuplicate(a):
mySet = set()
for i in range(len(a)):
if a[i] in mySet:
return a[i]
else:
mySet.add(a[i])
return -1
function firstDuplicate($a) {
foreach($a as $index => $value) {
$detector[] = $value;
$counter = 0;
foreach($detector as $item) {
if($item == $value) {
$counter++;
if($counter >= 2) {
return $value;
break;
}
}
}
}
return -1;
}
It's easy to just get the first number that will be checked as duplicated, but unfortunately, this function exceeded 4 seconds with a large array of data, so please using it with a small scale of array data.
EDIT
I have new own code fixes execution time for large array data
function firstDuplicate($a) {
$b = [];
$counts = array_count_values($a);
foreach($counts as $num => $duplication) {
if($duplication > 1) {
$b[] = $num;
}
}
foreach($a as $value) {
if(in_array($value, $b)) {
$detector[] = $value;
$counter = 0;
foreach($detector as $item) {
if($item == $value) {
$counter++;
if($counter >= 2) {
return $value;
break;
}
}
}
}
}
return -1;
}
The new code target the current numbers having a reputation only by using array_count_values()
function firstDuplicate($a) {
$indexNumber = -1;
for($i = count($a); $i >= 1 ; --$i){
for($k = 0; $k < $i; $k++){
if(isset($a[$i]) && ($a[$i] === $a[$k]) ){
$indexNumber = $a[$k];
}
}
}
return $indexNumber;
}
Remove error from undefined index array.

php array sorting with next value difference

can anyone help me with this following Array sorting
Input
$array=array(1,2,3,6,7,8,100,101,200);
Output:
$new_array=array(
0=>array(1,2,3),
1=>array(6,7,8),
2=>array(100,101),
3=>array(200)
);
Thanks in advance!
$array=array(1,2,3,6,7,8,100,101,200);
$new_array = array();
$lastNumber = '';
foreach($array as $number) {
if($lastNumber === '') {
$otherArray = array($number);
}
elseif($lastNumber + 1 !== $number) {
$new_array[] = $otherArray;
$otherArray = array($number);
}
else{
$otherArray[] = $number;
}
$lastNumber = $number;
}
$new_array[] = $otherArray;
print_r($new_array);
You can loop over the array and check the distance to the next element in the array. If this distance is larger then one add a new sub array:
$array=array(1,2,3,6,7,8,100,101,200);
$result=array(array());
for($i=0; $i<count($array)-1; $i++)
{
if($array[$i+1]-$array[$i]==1)
{
// If difference to next number is one -> push
array_push($result[count($result)-1], $array[$i]);
}
else
{
// ... else: Push and create new array for the next element
array_push($result[count($result)-1], $array[$i]);
array_push($result, array());
}
}
// Push the last number
array_push($result[count($result)-1], $array[$i]);
print_r($result);
Just a different approach with array_push()...
Pretty simple: loop through the numbers, remember the last one, if the current number is not the successor of the last one, add a new array to your result, push into the last array in your result.
$result = [];
$last = null;
foreach ($array as $number) {
if ($last !== $number - 1) {
$result[] = [];
}
$result[count($result) - 1][] = $number;
$last = $number;
}
You could even get rid of $last and directly read the last array element of the last array element of $result, but that would make the code actually more complicated.

How can I find not just duplicates in array, but numbers that match a range in PHP?

I need to find not just duplicates in an array, but numbers that are within 1 of each other.
example: $myArr = array(46,78,77,43,86,1,47,14,51,31)
How would I get find those numbers if there no duplicates were found?
Thanks.
This will work - tested:
$myArr = array(46,78,77,43,86,1,47,14,51,31);
$i = 1;
while($i <= 99){
if(in_array($i, $myArr)){
// This means it's in the array
// Let's see if it's +1 of the last #
if(isset($last_num)){
$res = ($i + 1);
if(in_array($res, $myArr)){
echo $res . ' is in the array<br>';
}
}
}
$last_num = $i;
$i++;
}
Could use something like this.
<?
$haystack = array(31,46,78,77,43,86,1,47,14,51,31);
array_walk($haystack, function($key, $value) use ($haystack) {
$needle = array($key - 1, $key, $key + 1);
$r = array_intersect($haystack, $needle);
if(count($r) > 1) { unset($r[$value]); print_r(array_values($r)); }
});
?>
Or if you want them returned in an array:
<?
$haystack = array(31,46,78,77,43,86,1,47,14,51,31);
$result = array_filter(array_map(function($key, $value) use ($haystack) {
$needle = array($key - 1, $key, $key + 1);
$r = array_intersect($haystack, $needle);
if(count($r) > 1) { unset($r[$value]); return array_values($r)['0']; }
}, $haystack));
print_r($result);
?>
A little more verbose, but it may be more efficient since we're only looping through the array when necessary. It will return the keys of the original array where duplicates and values within range are found. (Note: I've expanded the code out a lot more than I normally would just for readability for OP)
/**
* Find the any values within an array that are within
* the specified range from another value.
*
* #param Array Array to search in
* #param uint Unsigned integer used for comparison
* #return Array The keys of all found values
**/
function findWithinRange(Array $array, $range) {
// sort the array values numerically
// so we don't have to loop through
// the entire array for each check
asort($array, SORT_NUMERIC);
// Keep the keys in case it's an associative array
$keys = array_keys($array);
// Get the values without the keys so we can easily loop
$values = array_values($array);
$return = array();
// Loop over each item in the array
foreach( $values as $k => $v ) {
$start = $k;
$min = $v - $range;
$max = $v + $range;
// track backwards in the array until we're less than range
// We could use array_search, but we'd be calling it multiple times
// This only runs through the array once and dies the moment
// it is out of the specified range
while(true) {
$k--;
if( !isset($values[$k]) ) {
break; // don't continue if we run out of keys
}
$curVal = $values[$k];
if( $curVal >= $min ) {
$return[] = $keys[$k];
}
else {
break; // kill the while loop if we're outside of range
}
}
// reset
$k = $start;
// track forward in the array until we're greater than range
while(true) {
$k++;
if( !isset($values[$k]) ) {
break; // don't continue if we run out of keys
}
$curVal = $values[$k];
if( $curVal <= $max ) {
$return[] = $keys[$k];
}
else {
break; // kill the while loop if we're outside of range
}
}
}
// drop duplicate reports
$return = array_unique($return);
// return all found keys
return $return;
}
Example usage:
$myArr = array(46,78,77,43,86,1,47,14,51,31);
$res = findWithinRange($myArr, 1);
var_export($res);
// array(6, 0, 1, 2)

Find the second highest variable in array

I would like to find the second highest variable in an array.
For example if I have:
$cookies = array(
"chocolate" => "20",
"vanilla" => "14",
"strawberry" => "18",
"raspberry" => "19",
"bluebery" => "29"
);
I can use max($cookies) to find the highest variable, which is "bluebery" => "29".
But how do I find the second highest? "chocolate" => "20"
Sort it and get the second item is the easiest way:
arsort($cookies);
$keys = array_keys($cookies);
echo $keys[1]; // chocolate
echo $cookies[$keys[1]]; // 20
If you want a more efficient way, you can also do it manually, by keeping track of both the highest and second-highest items at the same time:
function secondMax($arr) {
$max = $second = 0;
$maxKey = $secondKey = null;
foreach($arr as $key => $value) {
if($value > $max) {
$second = $max;
$secondKey = $maxKey;
$max = $value;
$maxKey = $key;
} elseif($value > $second) {
$second = $value;
$secondKey = $key;
}
}
return array($secondKey, $second);
}
Usage:
$second = secondMax($cookies);
echo "{$second[0]} => {$second[1]}"; // chocolate => 20
For fun you could use max() twice :)
For example:
Duplicate the array
Run max()
Remove the max
Run max() again
The alternative would to sort the array based on values and get the second element of the array. I'd be curious which is faster. Likely the sort.
arsort($cookies) AND array_shift($cookies) AND list($k, $v) = each($cookies);
echo "$k => $v"; // chocolate => 20
rsort($cookies);
echo $cookies[1];
Try :
asort($cookies);
end($cookies);
prev($cookies);
list($key,$value) = each($cookies);
or reverse it
arsort($cookies);
reset($cookies);
next($cookies);
list($key,$value) = each($cookies);
** Edit **
I thought I'd share this anyway, if someone would stumble across this and need it :
/**
* Returns the key => value pair with the specific rank.
* if $rank is 0, falase is returned. If $rank is positive,
* then the $rank th smallest pair is returned. If $rank
* is negative, then the $rank th biggest pair is returned.
* If $rank range is outside the size of the array, false
* is returned. If a callable function is provided, it will
* be used to sort the data. If $keySort is true, then the
* data will be sorted by keys instead (the callback functions
* will receive the keys to compare instead of values)
*
* #param $data array
* #param $rank int
* #param $cmd_function callable (optional)
* #param $keySort boolean (optional)
* #return array the key => value pair or false
*/
function findByRank($data, $rank, $cmd_function = null, $keySort = false) {
if (($rank == 0) || (abs($rank) > count($data))) {
return false;
}
$sort = ($keySort?'k':'a').'sort';
if ($cmd_function != null) {
$sort = 'u'.$sort;
$sort($data, $cmd_function);
} else {
$sort($data);
}
if ($rank > 0) {
reset($data);
$next = 'next';
} else {
end($data);
$next = 'prev';
$rank = abs($rank);
}
while (--$rank > 0) $next($data);
return each($data);
}
$cookies = array(
"chocolate" => "20",
"vanilla" => "14",
"strawberry" => "18",
"raspberry" => "19",
"bluebery" => "29"
);
header('Content-type:text/plain; charset=utf-8');
var_dump(findByRank($cookies, -10)); // -> false
var_dump(findByRank($cookies, -2)); // -> 'chocolate' key=>value pair
var_dump(findByRank($cookies, -1)); // -> 'blueberry' key=>value pair
var_dump(findByRank($cookies, 0)); // -> false
var_dump(findByRank($cookies, 1)); // -> 'vanilla' key=>value pair
var_dump(findByRank($cookies, 3)); // -> 'raspberry' key=>value pair
Sort the array descending and take the second value. Or, to be save, take the first value and go through the array until you find a smaller one.
function second_largest($arr)
{
sort($arr, SORT_NUMERIC);
return($arr[count($arr) - 2]);
}
//echo 3
echo second_largest(array(0, 3, 4, 1, 2));
Check this URL
http://maheshbokkisam.blogspot.in/2013/04/find-nth-highest-value-in-array-without.html
Find Nth/ N th highest value from given array without using any sorting in PHP
$ar = array(23,56,87,12,98,85,24,54,99,100,1,4,5,2,76,37,92);
$n = count($ar) - 5;
for($i = 0; $i < $n; $i++){
// Get the max value from array // get the Nth value from last loop
echo $a = max($ar);
echo "<br /><pre>"; print_r($ar);
$ar = array_flip($ar); // Flip the array
//print_r($ar);
unset($ar[$a]); // Unset the max value from array
//print_r($ar);
$ar = array_flip($ar); // Flip the array
echo "</pre>";
echo "<hr />";
}
<?php
// Finding Second highest number (In case of index of array is random)
$arr = [-5 => 33, -4 => -2, 8 => 0, 44, 44, 44, 44, 44];
$max = -INF;
$secondMax = -INF;
$size = sizeof($arr);
if ($size > 1) {
foreach ($arr as $key => $value) {
echo "KEY-> ", $key, "VALUE->", $value, "\n";
if ($value > $max) {
$max = $value;
} else {
if ($value < $max && $value > $secondMax) {
$secondMax = $value;
}
}
}
} else if ($size == 0) {
$max = "No Max element";
$secondMax = "No Second highest element";
} else {
foreach ($arr as $key => $value) {
$max = $arr[$key];
$secondMax = "No second highest element";
}
}
echo "maxvalue = ", $max, "\n";
echo "secondmax =", $secondMax;

Categories