Related
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;
}
}
I have this array:
$array = array(a, b, c, d, e, f, g);
I want to split it in two arrays depending if the index is even or odd, like this:
$odd = array(a, c, e, g);
$even = array(b, d, f);
Thanks in advance!
One solution, using anonymous functions and array_walk:
$odd = array();
$even = array();
$both = array(&$even, &$odd);
array_walk($array, function($v, $k) use ($both) { $both[$k % 2][] = $v; });
This separates the items in just one pass over the array, but it's a bit on the "cleverish" side. It's not really any better than the classic, more verbose
$odd = array();
$even = array();
foreach ($array as $k => $v) {
if ($k % 2 == 0) {
$even[] = $v;
}
else {
$odd[] = $v;
}
}
Use array_filter (PHP >= 5.6):
$odd = array_filter($array, function ($input) {return $input & 1;}, ARRAY_FILTER_USE_KEY);
$even = array_filter($array, function ($input) {return !($input & 1);}, ARRAY_FILTER_USE_KEY);
I am not sure if this is the most elegant way, but it should work a charm:
$odd=array();
$even=array();
$count=1;
foreach($array as $val)
{
if($count%2==1)
{
$odd[]=$val;
}
else
{
$even[]=$val;
}
$count++;
}
As an almost-one-liner, I think this will be my favourite:
$even = $odd = array();
foreach( $array as $k => $v ) $k % 2 ? $odd[] = $v : $even[] = $v;
Or for a tiny little more? speed:
$even = $odd = array();
foreach( $array as $k => $v ) ( $k & 1 ) === 0 ? $even[] = $v : $odd[] = $v;
A bit more verbose variant:
$both = array( array(), array() );
// or, if $array has at least two elements:
$both = array();
foreach( $array as $k => $v ) $both[ $k % 2 ][] = $v;
list( $even, $odd ) = $both;
With array_chunk:
$even = $odd = array();
foreach( array_chunk( $array, 2 ) as $chunk ){
list( $even[], $odd[] ) = isset( $chunk[1]) ? $chunk : $chunk + array( null, null );
// or, to force even and odd arrays to have the same count:
list( $even[], $odd[] ) = $chunk + array( null, null );
}
If $array is guaranteed to have even number of elements:
$even = $odd = array();
foreach( array_chunk( $array, 2 ) as $chunk )
list( $even[], $odd[] ) = $chunk;
PHP 5.5.0+ with array_column:
$chunks = array_chunk( $array, 2 );
$even = array_column( $chunks, 0 );
$odd = array_column( $chunks, 1 );
Something similar for older PHP versions.
The keys will be 0,2,4,… and 1,3,5,…. If you don't like this, apply an array_values too:
$even = array_intersect_key( $array, array_flip( range( 0, count( $array ), 2 )));
$odd = array_intersect_key( $array, array_flip( range( 1, count( $array ), 2 )));
or
$even = array_intersect_key( $array, array_fill_keys( range( 0, count( $array ), 2 ), null ));
$odd = array_intersect_key( $array, array_fill_keys( range( 1, count( $array ), 2 ), null ));
One more functional solution with array_chunk and array_map. The last line removes empty item from the 2nd array, when size of a source array is odd
list($odd, $even) = array_map(null, ...array_chunk($ar,2));
if(count($ar) % 2) array_pop($even);
Just loop though them and check if the key is even or odd:
$odd = array();
$even = array();
foreach( $array as $key => $value ) {
if( 0 === $key%2) { //Even
$even[] = $value;
}
else {
$odd[] = $value;
}
}
One
$odd = $even = array();
for ($i = 0, $l = count($array ); $i < $l;) { // Notice how we increment $i each time we use it below, by two in total
$even[] = $array[$i++];
if($i < $l)
{
$odd[] = $array[$i++];
}
}
Two
$odd = $even = array();
foreach (array_chunk($array , 2) as $chunk) {
$even[] = $chunk[0];
if(!empty( $chunk[1]))
{
$odd[] = $chunk[1];
}
}
Based on #Jon's second variant, I made this following for use with PHP Smarty v3 template engine. This is for displaying news/blog with both one or two columns template model.
After the MySql query I'll do the following code :
if(sizeof($results) > 0) {
$data = array();
foreach($results as $k => $res) {
if($k % 2 == 0) {
$res["class"] = "even";
$data["all"][] = $data["even"][] = $res;
}
else {
$res["class"] = "odd";
$data["all"][] = $data["odd"][] = $res;
}
}
}
I obtain an array of 3 sub-arrays (including odd/even class) with Smarty syntax of use :
all items {foreach $data.all as $article}...{/foreach}
odd items only {foreach $data.odd as $article}...{/foreach}
even items only {foreach $data.even as $article}...{/foreach}
Hope it helps some people...
$odd = [];
$even = [];
while (count($arr)) {
$odd[] = array_shift($arr);
$even[] = array_shift($arr);
}
<?php
$array1 = array(0,1,2,3,4,5,6,7,8,9);
$oddarray = array();
$evenarray = array();
$count = 1;
echo "Original: ";
foreach ($array1 as $value)
{
echo "$value";
}
echo "<br> Even: ";
foreach ($array1 as $print)
{
if ($count%2==1)
{
$evenarray = $print;
echo "$print";
}
$count++;
}
echo "<br> Odd: ";
foreach ($array1 as $print2) {
if ($count%2!=1)
{
$oddarray[] = $print2;
echo "$print2";
}
$count++;
}
?>
Output:
Original: 0123456789
Even: 02468
Odd: 13579
I'm trying to sort an array numerically but the integers are found in the middle of a value, not on the first character. Here is what my array looks like (using dummy values):
$array = Array('A25','A30','A40','B25','B30','B40','AB25','AB30','AB40');
sort($array,1);
Output after foreach:
A25
A30
A40
AB25
AB30
AB40
B25
B30
B40
Expected output:
A25
AB25
B25
A30
AB30
B30
A40
AB40
B40
What would be the best sorting method for this? Really appreciate it, thanks!
$array = Array('A25','A30','A40','B25','B30','B40','AB25','AB30','AB40');
usort(
$array,
function($a, $b) {
list($achar,$anum) = sscanf($a, '%[A-Z]%d');
list($bchar,$bnum) = sscanf($b, '%[A-Z]%d');
if ($anum > $bnum) {
return 1;
} elseif (($anum == $bnum) && ($achar > $bchar)) {
return 1;
}
return -1;
}
);
var_dump($array);
Have created a custom function depending on your requirement, please see below code
<?php
$array = array('A30','A25','ZZZ','A40','Rohan','B25','B30','Sakhale','B40','AB25','AB30','AB40');
$array = sortArrayByNumber($array);
var_dump($array);
/**
* #name sortArrayByNumber
* #abstract sort the entire array irrespective of the string, but the numbers into it
* also we append the elements not having any number at the end
* #author Rohan Sakhale
*/
function sortArrayByNumber($arr){
$sortedArr = array();
$tempArray = array();
$stringOnlyArray = array();
foreach($arr as $v){
$num = getNumberFromString($v);
/**
* If no number found, append it into stringOnlyArray
*/
if($num == ''){
$stringOnlyArray[] = $v;
continue;
}
if(!isset($tempArray[$num])){
$tempArray[$num] = array();
}
$tempArray[$num][] = $v;
}
$tempArrayKeys = array_keys($tempArray);
sort($tempArrayKeys);
foreach($tempArrayKeys as $key){
sort($tempArray[$key]);
$sortedArr = array_merge($sortedArr, $tempArray[$key]);
}
if(count($stringOnlyArray) > 0){
sort($stringOnlyArray);
$sortedArr = array_merge($sortedArr, $stringOnlyArray);
}
return $sortedArr;
}
/**
* #str - String param which tend to have number
*/
function getNumberFromString($str){
$matches = null;
preg_match_all('!\d+!', $str, $matches);
if(!is_null($matches) and is_array($matches)){
if(isset($matches[0][0])){
return $matches[0][0];
}
}
return '';
}
?>
Here sort by number method is trying to firstly identify the number's in your string and maintain a separate array of it based on the keys, later we sort in ascending order every key's of number and then we finally merge it into sorted array
You can use user defined function with usort to achieve it
<?php
function mySort($a,$b) {
$numA = '';
$strA = '';
$numB = '';
$strB = '';
for($i=0;$i<strlen($a); $i++) {
if(is_numeric($a[$i])) {
$numA .= (string)$a[$i];
}
else {
$strA .= $a[$i];
}
}
for($i=0;$i<strlen($b); $i++) {
if(is_numeric($b[$i])) {
$numB .= (string)$b[$i];
}
else {
$strB .= $b[$i];
}
}
$numA = (int)$numA;
$numB = (int)$numB;
if($numA>$numB) {
return true;
}
elseif($numA<$numB) {
return false;
}
else {
if(strcmp($strA,$strB)>0) {
return true;
}
else {
return false;
}
}
}
$array = Array('A25','A30','A40','B25','B30','B40','AB25','AB30','AB40');
var_dump($array);
usort($array,'mySort');
var_dump($array);
?>
Here's a stable sort, the result is: "A25" "B25" "AB25" "A30" "B30" "AB30" "A40" "B40" "AB40" .
function getNum($str)
{
preg_match ( '/(\d+)$/', $str, $match );
return intval ( $match [1] );
}
function stableSort($arr)
{
$newArr = array ();
foreach ( $arr as $idx => $ele )
{
$newArr [] = array (
'idx' => $idx,
'val' => $ele
);
}
usort ( $newArr,
function ($a, $b)
{
$d = getNum ( $a ['val'] ) - getNum ( $b ['val'] );
return $d ? $d : $a ['idx'] - $b ['idx'];
} );
$sortArr = array ();
foreach ( $newArr as $ele )
{
$sortArr [] = $ele ['val'];
}
return $sortArr;
}
var_dump ( stableSort ( $array ) );
U can use various kinds of ways to sort arrays in PHP. PHP has some good ways build in to do sorting on arrays. In this case I agree with Mark Baker, however I would recommend a preg_replace to get the numeric value of your strings.
$array = Array('A25','A30','A40','B25','B30','B40','AB25','AB30','AB40');
function cmp($a, $b)
{
$v1 = preg_replace("/[^0-9]/", "", $a);
$v2 = preg_replace("/[^0-9]/", "", $b);
if ($v1 == $v2) {
return 0;
}
return ($v1 < $v2) ? -1 : 1;
}
usort($array, "cmp");
var_dump($array);
Look into the PHP information about sorting arrays, php.net/usort and various others.
Instead of just 1, how can I pick the 4 highest values from an array using max()?
You could use an SplMaxHeap
function maxN(array $numbers, $n)
{
$maxHeap = new SplMaxHeap;
foreach($numbers as $number) {
$maxHeap->insert($number);
}
return iterator_to_array(
new LimitIterator($maxHeap, 0, $n)
);
}
Usage (demo):
print_r( maxN( array(7,54,2,4,26,7,82,4,34), 4 ) );
You could try this:
$a = array(3,5,6,1,23,6,78,99);
asort($a);
var_dump(array_slice($a, -4));
HTH.
This will do it in Θ(n) time:
$a = $b = $c = $d = null;
foreach($array as $v) {
if(!isset($a) || $v > $a) {
$d = $c;
$c = $b;
$b = $a;
$a = $v;
}elseif(!isset($b) || $v > $b) {
$d = $c;
$c = $b;
$b = $v;
}elseif(!isset($c) || $v > $c) {
$d = $c;
$c = $v;
}elseif(!isset($d) || $v > $d) {
$d = $v;
}
}
$result = array($a, $b, $c, $d);
function maxs($ar, $count=4)
{
$res = array();
foreach ($ar as $v)
{
for ($i = 0;$i < $count;$i++)
{
if ($i >= count($res) || $v > $res[$i])
{
do
{
$tmp = $res[$i];
$res[$i] = $v;
$v = $tmp;
$i++;
}
while ($i < $count);
break;
}
}
}
return $res;
}
A simple method using php predefined functions.
<?php
$arr = array(6, 8, 3, 2, 7, 9);
rsort($arr);
$first = array_shift($arr);
$second = array_shift($arr);
$third = array_shift($arr);
echo $first; // print 9
echo $second; // print 8
echo $third; // print 7
?>
While storing itself you can maintain another array as soon as the new item is inserted check with the max value in the inner array if the item being inserted is greater insert this item. During the item pop do viceversa. From the inner maintained array you can get as many max numbers as possible.
Eg:
$array= array(array(141,151,161),2,3,array(101,202,array(303,606)));
output :606
What you need is to recursively go through your array ; which means the max function, which is not recursive, will not be "enough".
But, if you take a look at the users's notes on the manual page of max, you'll find this note from tim, who proposes this recursive function (quoting) :
function multimax( $array ) {
// use foreach to iterate over our input array.
foreach( $array as $value ) {
// check if $value is an array...
if( is_array($value) ) {
// ... $value is an array so recursively pass it into multimax() to
// determine it's highest value.
$subvalue = multimax($value);
// if the returned $subvalue is greater than our current highest value,
// set it as our $return value.
if( $subvalue > $return ) {
$return = $subvalue;
}
} elseif($value > $return) {
// ... $value is not an array so set the return variable if it's greater
// than our highest value so far.
$return = $value;
}
}
// return (what should be) the highest value from any dimension.
return $return;
}
Using it on your array :
$arr= array(array(141,151,161),2,3,array(101,202,array(303,404)));
$max = multimax($arr);
var_dump($max);
Gives :
int 404
Of course, this will require a bit more testing -- but it should at least be a start.
(Going through the users' notes on manual pages is always a good idea : if you're having a problem, chances are someone else has already had that problem ;-) )
Same idea as Pascal's solution, only shorter thanks to the Standard PHP Library
$arr= array(array(141,151,161),2,3,array(101,202,array(303,404)));
echo rmax($arr);
function rmax(array $arr) {
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));
// initialize $max
$it->next(); $max = $it->current();
// "iterate" over all values
foreach($it as $v) {
if ( $v > $max ) {
$max = $v;
}
}
return $max;
}
http://www.java2s.com/Code/Php/Data-Structure/FindtheMaximumValueinaMultidimensionalArray.htm
function recursive_array_max($a) {
foreach ($a as $value) {
if (is_array($value)) {
$value = recursive_array_max($value);
}
if (!(isset($max))) {
$max = $value;
} else {
$max = $value > $max ? $value : $max;
}
}
return $max;
}
$dimensional = array(
7,
array(3, 5),
array(5, 4, 7, array(3, 4, 6), 6),
14,
2,
array(5, 4, 3)
);
$max = recursive_array_max($dimensional);
$arr = array(array(141,151,161), 2, 3, array(101, 202, array(303,404)));
$callback = function ($value, $key) use (&$maximo) {
if( $value > $maximo){
$maximo = $value;
}
};
array_walk_recursive($arr, $callback);
echo '<pre>'; print_r($maximo);``
A more elegant solution:
function MaxArray($arr)
{
function findMax($currentValue, $currentKey)
{
global $maxValue;
$maxValue = ($currentValue > $maxValue ? $currentValue : $maxValue);
}
array_walk_recursive($arr, 'findMax');
return $GLOBALS['maxValue'];
}
It's very simple
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($arr));
$max = max(iterator_to_array($iterator, false));
Finding the max avoiding too much recursion :
function array_max(array $array) {
$context = func_get_args();
$max = -INF;
while (!empty($context)) {
$array = array_pop($context);
while (!empty($array)) {
$value = array_pop($array);
if (is_array($value)) {
array_push($context, $value);
}
elseif ($max < $value) {
$max = $value;
}
}
}
return $max;
}
A more general method avoiding too much recursion :
function array_reduce_recursive($default, array $array, $callback = null) {
$context = func_get_args();
$count = func_num_args();
if (is_callable(func_get_arg($count - 1))) {
$callback = array_pop($context);
}
else {
$callback = create_function('$x, $y', 'return $x < $y ? $y : $x;');
}
$reduced = array_shift($context);
while (!empty($context)) {
$array = array_pop($context);
while (!empty($array)) {
$value = array_pop($array);
if (is_array($value)) {
array_push($context, $value);
}
else {
$reduced = $callback($reduced, $value);
}
}
}
return $reduced;
}
function array_max_recursive() {
$args = func_get_args();
$callback = create_function('$x, $y', 'return $x < $y ? $y : $x;');
return array_reduce_recursive(-INF, $args, $callback);
}
By this way you can specify the callback method if you are looking for something else than the biggest number. Also this method takes several arrays.
The end way is less efficient of course.
With this you have a full compatibility with lot of PHP version.
function MaxArray($arr) {
$maximum = 0;
foreach ($arr as $value) {
if (is_array($value)) {
//print_r($value);
$tmaximum = MaxArray($value);
if($tmaximum > $maximum){
$maximum = $tmaximum;
}
}
else
{
//echo $value.'\n';
if($value > $maximum){
$maximum = $value;
}
}
}
return $maximum;
}