I have an array with about 360 keys:
$threadColours['Apricot'] = array(250,180,160,3341,328,826,194,3332,0);
$threadColours['Apricot, Light'] = array(255,230,225,3824,8,833,2605,-1,1);
$threadColours['Apricot, Medium'] = array(255,135,105,3340,329,827,193,-1,2);
I am retrieving a pixel rgb values that came from this array. So I need to get the key where, for example, $threadColours[???][0]=250, [1]=180, [2]=160. I know you can search for a single key but I cannot figure out how to match multiple values. Just to be clear, I have the rgb values I just want to know how to get the key that has all three values in [0],[1],[2] respectively.
Thank you much,
Todd
function getColourKey($colours, $r, $g, $b) {
foreach ($colours as $key => $value)
if ($value[0] == $r && $value[1] == $g && $value[2] == $b)
return $key;
return NULL;
}
You can use code like this:
$threadColours['Apricot'] = array(250,180,160,3341,328,826,194,3332,0);
$threadColours['Apricot, Light'] = array(255,230,225,3824,8,833,2605,-1,1);
$threadColours['Apricot, Medium'] = array(255,135,105,3340,329,827,193,-1,2);
$needle=array(2605,-1,1); // this is your r,g,b
$startIndex = -1;
$rootElem = "";
foreach ($threadColours as $key => $arr) {
for ($i=0; $i < count($arr); $i+=3) {
if ( $arr[$i] == $needle[0] &&
$arr[$i+1] == $needle[1] &&
$arr[$i+2] == $needle[2]
) {
$rootElem = $key;
$startIndex = $i;
break;
}
}
}
printf("rootElem=[%s], startIndex=[%s]\n", $rootElem, $startIndex);
OUTPUT:
rootElem=[Apricot, Light], startIndex=[6]
$search = array(250, 180, 160);
$color = null;
foreach ($threadColours as $key => $val) {
if (array_slice($val, 0, 3) == $search) {
$color = $key;
break;
};
}
Related
Let's say I have an array like that:
[12,3,4,5,8,9,11,20]
and a given number 7, then the predecessor/successor from the array would be 5/8 How do I find these numbers in an effective way?
At the moment I have the solution only for finding the successor via comparison.
Your need to iterate over the array and compare every number, than save the number, if it is more close to your needle, than the old one:
function precessorAndSuccessor(array $numbers, int $needle){
$pre = NULL;
$suc = NULL;
foreach($numbers as $number){
if($number < $needle){
if($pre === NULL || $pre < $number){
$pre = $number;
}
}elseif($number > $needle){
if($suc === NULL || $suc > $number){
$suc = $number;
}
}
}
return [
"predecessor" => $pre,
"successsor" => $suc
];
}
``
If you sort the array then just run through and check:
$num = 7;
$pre = $suc = false;
sort($array);
foreach($array as $v) {
if($v < $num) { $pre = $v; }
if($v > $num) { $suc = $v; break; }
}
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;
}
}
So I have a collection of integer values, which is built from a result of another function that can have different values every time. Consider the following in PHP:
$arr = [0,0,2,2,0,0,0,3,3];
Which i need to convert to:
$newArr = [null,0,2,2,0,null,0,3,3];
What i want to accomplish is: If a value is > 0, its neighbours should be 0, and the rest should be null.
What is the best strategy here?
Playing with operator precedence:
$zero = true;
$arr = [0,0,2,2,0,0,0,3,3];
$newArr = [];
foreach($arr as $k=>$v) {
if ($v) {
$newArr[] = $v;
$zero = false;
} else {
if ($zero and isset($arr[$k+1]) && !$arr[$k+1] || !isset($arr[$k+1]))
$newArr[] = null;
else
$newArr[] = 0;
$zero = true;
}
}
print_r($newArr);
Looping through the entire array, we evaluate each element for three conditions:
1.Element is zero.
2.Previous element is set, and it is equal to zero or null.
3.Next element is set, and it is equal to zero or null.
<?php
foreach($array as $key => $element)
{
if($element == 0 && ((isset($array[$key - 1]) && !$array[$key - 1]) || (isset($array[$key + 1]) && !$array[$key + 1])))
{
$array[$key] = null;
}
}
?>
I think it should work for you:
<?php
$arr = [0,0,2,2,0,0,0,3,3];
$new_array = $arr;
$array_count = count($arr);
for ($i=0; $i<$array_count; $i++) {
if ($i == 0 && $arr[$i+1] == 0) {
$new_array[$i] = null;
} elseif ($i == ($array_count-1) && $arr[$i-1] == 0) {
$new_array[$i] = null;
} elseif ($arr[$i-1] == 0 && $arr[$i+1] == 0) {
$new_array[$i] = null;
}
}
echo "<pre>";
print_r($new_array);
?>
We need to check for three conditions: is there, prev. is zero and next is zero.
You can combine first two conditions into the third one.
Broke it down for simplicity.
$array = [0,0,2,2,0,0,0,3,3];
$newArray = [];
foreach ($array as $key => $val) {
$previous = NULL;
$next = NULL;
if (isset($array[$key + 1])) {
$next = $array[$key + 1];
}
if ($key != 0) {
$previous = $array[$key - 1];
}
if ($val === 0 && $next == 0 && $previous == 0) {
$newArray[] = 'NULL';
} else {
$newArray[] = $val;
}
}
Another way to do this:
$arr = [0,0,2,2,0,0,0,3,3];
foreach($arr as $key => $value){
if($arr[$key] > 0 && isset($arr[$key - 1]) && $arr[$key - 1] == 0){
if(isset($arr[$key - 2]) && $arr[$key - 2] == 0){
$arr[$key - 2] = null;
}
}
if($arr[$key] > 0 && isset($arr[$key + 1]) && $arr[$key + 1] == 0){
if(isset($arr[$key + 2]) && $arr[$key + 2] == 0){
$arr[$key + 2] = null;
}
}
}
echo '<pre>';
print_r($arr);
echo '</pre>';
Here, i am looking for the positive value first then checking and if neighbor is 0 then set neighbor's neighbor to null.
<?php
$arr = [0,0,2,2,0,0,0,3,3];
$extra = [];
for($x=0; $x<count($arr); $x++){
if($arr[$x] == 0){
$tmp = isset($tmp)?$tmp:[];
$tmp[]=$x;
}else{
if(isset($tmp)){
$extra[] = $tmp;
unset($tmp);
}
}
}
foreach($extra as $subArr){
if(count($subArr) == 2){
$arr[$subArr[0]] = null;
$arr[$subArr[1]] = 0;
}else if(count($subArr) == 3){
$arr[$subArr[0]] = 0;
$arr[$subArr[1]] = null;
$arr[$subArr[2]] = 0;
}
}
var_dump($arr);
// YIELDS::
array (size=9)
0 => null
1 => int 0
2 => int 2
3 => int 2
4 => int 0
5 => null
6 => int 0
7 => int 3
8 => int 3
I have a PHP array which looks like this example:
$array[0][0] = 'apples';
$array[0][1] = 'pears';
$array[0][2] = 'oranges';
$array[1][0] = 'steve';
$array[1][1] = 'bob';
And I would like to be able to produce from this a table with every possible combination of these, but without repeating any combinations (regardless of their position), so for example this would output
Array 0 Array 1
apples steve
apples bob
pears steve
pears bob
But I would like for this to be able to work with as many different arrays as possible.
this is called "cartesian product", php man page on arrays http://php.net/manual/en/ref.array.php shows some implementations (in comments).
and here's yet another one:
function array_cartesian() {
$_ = func_get_args();
if(count($_) == 0)
return array(array());
$a = array_shift($_);
$c = call_user_func_array(__FUNCTION__, $_);
$r = array();
foreach($a as $v)
foreach($c as $p)
$r[] = array_merge(array($v), $p);
return $r;
}
$cross = array_cartesian(
array('apples', 'pears', 'oranges'),
array('steve', 'bob')
);
print_r($cross);
You are looking for the cartesian product of the arrays, and there's an example on the php arrays site: http://php.net/manual/en/ref.array.php
Syom copied http://www.php.net/manual/en/ref.array.php#54979 but I adapted it this to become an associative version:
function array_cartesian($arrays) {
$result = array();
$keys = array_keys($arrays);
$reverse_keys = array_reverse($keys);
$size = intval(count($arrays) > 0);
foreach ($arrays as $array) {
$size *= count($array);
}
for ($i = 0; $i < $size; $i ++) {
$result[$i] = array();
foreach ($keys as $j) {
$result[$i][$j] = current($arrays[$j]);
}
foreach ($reverse_keys as $j) {
if (next($arrays[$j])) {
break;
}
elseif (isset ($arrays[$j])) {
reset($arrays[$j]);
}
}
}
return $result;
}
I needed to do the same and I tried the previous solutions posted here but could not make them work. I got a sample from this clever guy http://www.php.net/manual/en/ref.array.php#54979. However, his sample did not managed the concept of no repeating combinations. So I included that part. Here is my modified version, hope it helps:
$data = array(
array('apples', 'pears', 'oranges'),
array('steve', 'bob')
);
$res_matrix = $this->array_cartesian_product( $data );
foreach ( $res_matrix as $res_array )
{
foreach ( $res_array as $res )
{
echo $res . " - ";
}
echo "<br/>";
}
function array_cartesian_product( $arrays )
{
$result = array();
$arrays = array_values( $arrays );
$sizeIn = sizeof( $arrays );
$size = $sizeIn > 0 ? 1 : 0;
foreach ($arrays as $array)
$size = $size * sizeof( $array );
$res_index = 0;
for ( $i = 0; $i < $size; $i++ )
{
$is_duplicate = false;
$curr_values = array();
for ( $j = 0; $j < $sizeIn; $j++ )
{
$curr = current( $arrays[$j] );
if ( !in_array( $curr, $curr_values ) )
{
array_push( $curr_values , $curr );
}
else
{
$is_duplicate = true;
break;
}
}
if ( !$is_duplicate )
{
$result[ $res_index ] = $curr_values;
$res_index++;
}
for ( $j = ( $sizeIn -1 ); $j >= 0; $j-- )
{
$next = next( $arrays[ $j ] );
if ( $next )
{
break;
}
elseif ( isset ( $arrays[ $j ] ) )
{
reset( $arrays[ $j ] );
}
}
}
return $result;
}
The result would be something like this:
apples - steve
apples - bob
pears - steve
pears - bob
oranges - steve
oranges - bob
If you the data array is something like this:
$data = array(
array('Amazing', 'Wonderful'),
array('benefit', 'offer', 'reward'),
array('Amazing', 'Wonderful')
);
Then it will print something like this:
Amazing - benefit - Wonderful
Amazing - offer - Wonderful
Amazing - reward - Wonderful
Wonderful - benefit - Amazing
Wonderful - offer - Amazing
Wonderful - reward - Amazing
foreach($parentArray as $value) {
foreach($subArray as $value2) {
$comboArray[] = array($value, $value2);
}
}
Don't judge me..
This works I think - although after writing it I realised it's pretty similar to what others have put, but it does give you an array in the format requested. Sorry for the poor variable naming.
$output = array();
combinations($array, $output);
print_r($output);
function combinations ($array, & $output, $index = 0, $p = array()) {
foreach ( $array[$index] as $i => $name ) {
$copy = $p;
$copy[] = $name;
$subIndex = $index + 1;
if (isset( $array[$subIndex])) {
combinations ($array, $output, $subIndex, $copy);
} else {
foreach ($copy as $index => $name) {
if ( !isset($output[$index])) {
$output[$index] = array();
}
$output[$index][] = $name;
}
}
}
}
#user187291
I modified this to be
function array_cartesian() {
$_ = func_get_args();
if (count($_) == 0)
return array();
$a = array_shift($_);
if (count($_) == 0)
$c = array(array());
else
$c = call_user_func_array(__FUNCTION__, $_);
$r = array();
foreach($a as $v)
foreach($c as $p)
$r[] = array_merge(array($v), $p);
return $r;
}
so it returns that all-important empty array (the same result as no combinations) when you pass 0 arguments.
Only noticed this because I'm using it like
$combos = call_user_func_array('array_cartesian', $array_of_arrays);
function array_comb($arrays)
{
$result = array();
$arrays = array_values($arrays);
$sizeIn = sizeof($arrays);
$size = $sizeIn > 0 ? 1 : 0;
foreach ($arrays as $array)
$size = $size * sizeof($array);
for ($i = 0; $i < $size; $i ++)
{
$result[$i] = array();
for ($j = 0; $j < $sizeIn; $j ++)
array_push($result[$i], current($arrays[$j]));
for ($j = ($sizeIn -1); $j >= 0; $j --)
{
if (next($arrays[$j]))
break;
elseif (isset ($arrays[$j]))
reset($arrays[$j]);
}
}
return $result;
}
I had to make combinations from product options. This solution uses recursion and works with 2D array:
function options_combinations($options) {
$result = array();
if (count($options) <= 1) {
$option = array_shift($options);
foreach ($option as $value) {
$result[] = array($value);
}
} else {
$option = array_shift($options);
$next_option = options_combinations($options);
foreach ($next_option as $next_value) {
foreach ($option as $value) {
$result[] = array_merge($next_value, array($value));
}
}
}
return $result;
}
$options = [[1,2],[3,4,5],[6,7,8,9]];
$c = options_combinations($options);
foreach ($c as $combination) {
echo implode(' ', $combination)."\n";
}
Elegant implementation based on native Python function itertools.product
function direct_product(array ...$arrays)
{
$result = [[]];
foreach ($arrays as $array) {
$tmp = [];
foreach ($result as $x) {
foreach ($array as $y) {
$tmp[] = array_merge($x, [$y]);
}
}
$result = $tmp;
}
return $result;
}
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;
}