How to get array key with less than values - php

I have 2 arrays:
$arr_1=array(200, 300, 200, 200);
$arr_2=array(
1 => array(70, 90, 70, 20),
2 => array(115, 150, 115, 35),
3 => array(205, 250, 195, 55),
4 => array(325, 420, 325, 95),
5 => array(545, 700, 545, 155)
);
Now I need some way to get array keys for arrays in $arr_1 where all their values are less than all values from $arr_2.
In the above example it must return key 1 AND key 2 from $arr_2 without using a foreach loop.

You can use array_filter to filter the elements (it preserves keys) and then pass the result to array_keys to receive an array of keys.
Also, your condition can be spelled this way: "return subarrays from $arr_2 where highest value is smaller than smallest value of $arr_1."
$arr_1=array(200, 300, 200, 200);
$arr_2=array(
1 => array(70, 90, 70, 20),
2 => array(115, 150, 115, 35),
3 => array(205, 250, 195, 55),
4 => array(325, 420, 325, 95),
5 => array(545, 700, 545, 155)
);
$filtered = array_filter($arr_2, function($value) use ($arr_1) {
return max($value) < min($arr_1);
});
$keys = array_keys($filtered);
var_dump($keys);

If you are only interested in comparing the subarrays against the lowest value in $arr_1, then best practices dictates that you declare that value before entering the array_filter(). This will spare the function having to call min() on each iteration. (Demo)
$arr_1=[200,300,200,200];
$arr_2=[
1=>[70,90,70,20],
2=>[115,150,115,35],
3=>[205,250,195,55],
4=>[325,420,325,95],
5=>[545,700,545,155]
];
$limit=min($arr_1); // cache this value, so that min() isn't called on each iteration in array_filter()
$qualifying_keys=array_keys(array_filter($arr_2,function($a)use($limit){return max($a)<$limit;}));
var_export($qualifying_keys);
/*
array(
0=>1,
1=>2,
)
*/

Related

PHP - Counting array elements in a specific range

I have an array with 950 elements. Values of elements are between 80-110. I want to count how many of them between 80-90, 90-100 and 100-110. Then I'll show them on a graph. Is this possible to count elements like that in php ?
You can simply do it by running a for loop. Create an array containing a range of elements and run a for loop. While you will run the loop on that time count the array element according to your given three groups. Finally you will get the total number of elements inside the given range. For your better help below I am giving an example :
<?php
$number = array(80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110);
$count1 = $count2 = $count3 = 0;
for ($i = 0; $i < sizeof($number); $i++) {
if($number[$i] >= 80 && $number[$i] <= 90 ) {
$count1++;
}
if($number[$i] >= 90 && $number[$i] <= 100 ) {
$count2++;
}
if($number[$i] >= 100 && $number[$i] <= 110 ) {
$count3++;
}
}
echo "The number between 80-90 = ".$count1."<br>";
echo "The number between 90-100 = ".$count2."<br>";
echo "The number between 100-110 = ".$count3."<br>";
?>
I think OP may have been going for a more pythonic answer (but in PHP)
//only valid in php 5.3 or higher
function countInRange($numbers,$lowest,$highest){
//bounds are included, for this example
return count(array_filter($numbers,function($number) use ($lowest,$highest){
return ($lowest<=$number && $number <=$highest);
}));
}
$numbers = [1,1,1,1,2,3,-5,-8,-9,10,11,12];
echo countInRange($numbers,1,3); // echoes 6
echo countInRange($numbers,-7,3); // echoes 7
echo countInRange($numbers,19,20); //echoes 0
the 'use' keyword indicates a 'closure' in php. Taken for granted in other languages, for example javascript, variables in an outer function are imported scope-wise into the inner function automatically (i.e. without special keywords), the inner function may also be called a "partial function".
For some reason in PHP 5.2x or lower, variables were not imported scope-wise automatically, and in PHP 5.3 or higher, the use keyword can overcome this. The syntax is very simple:
$functionHandle = function(<arguments>) use (<scope-imported variables>){
//...your code here...
}
To avoid having too many comparisons jump to next loop when you have determined where your number belongs.
function countOccurences( array $numbersArray ):array
{
$return = array('n80to90' => 0, 'n90to100' => 0, 'n100to110' => 0);
foreach( $numbersArray as $number ){
if( $number < 80 || $number > 110 )
continue;
if($number < 91){
$return['n80to90']++;
continue;
}
if($number < 101){
$return['n90to100']++;
continue;
}
$return['n100to110']++;
}
return $return;
}
I cannot imagine that your statistical graphic that would want to represent values on the cusp of two groups as belonging to both groups. For this reason, I'll offer a condition-less function-less technique which can be execute in a foreach loop.
Code: (Demo)
$sampleData = range(80, 110);
$result = array_fill_keys(['80s', '90s', '100s'], 0); // set 0 defaults for incrementation
foreach ($sampleData as $value) {
++$result[(10 * ((int)($value / 10) <=> 9) + 90) . 's'];
}
var_export($result);
Output:
array (
'80s' => 10,
'90s' => 10,
'100s' => 11,
)
My technique manufactures the appropriate keys from the values by:
Dividing by 10
Truncating the decimal (same effect as floor()
Making a 3-way comparison via the spaceship operator (returns -1, 0, or 1)
Multiplying the "-1|0|1" by 10
Adding 90
And finally concatenating an "s".
The ++ means add 1 to the current value of the element with the corresponding key.
Alternatively, if you wanted to group the values as "90+below" (80-90), "100+below" (91-100), and "110+below" (101-110), then it is a simple matter of adjusting the key-generating factors.
Instead of counting, I'll show the elements assigned to each group.
Code: (Demo)
$sampleData = range(80, 110);
foreach ($sampleData as $value) {
$result[(10 * ((int)(($value - 1) / 10) <=> 9) + 100) . '+under'][] = $value;
}
var_export($result);
Output:
array (
'90+under' =>
array (
0 => 80,
1 => 81,
2 => 82,
3 => 83,
4 => 84,
5 => 85,
6 => 86,
7 => 87,
8 => 88,
9 => 89,
10 => 90,
),
'100+under' =>
array (
0 => 91,
1 => 92,
2 => 93,
3 => 94,
4 => 95,
5 => 96,
6 => 97,
7 => 98,
8 => 99,
9 => 100,
),
'110+under' =>
array (
0 => 101,
1 => 102,
2 => 103,
3 => 104,
4 => 105,
5 => 106,
6 => 107,
7 => 108,
8 => 109,
9 => 110,
),
)

sort multidimensional array by values in PHP

I have an array fetched from mysql database tables of type. I want to sort it in order of particular value.
$arr1=array(array(12, 8, 5, 34),
array(54, 87, 32, 10),
array(23, 76, 98, 13),
array(53, 16, 24, 19));
How can i sort it by value?
Like sorting by 2nd value should result to.
$arr1=array(array(12, 8, 5, 34),
array(53, 16, 24, 19),
array(23, 76, 98, 13),
array(54, 87, 32, 10));
I like to use usort to solve these problems.
$sortKey = 1;
usort($arr1, function($a, $b) use($sortKey){
return $a[$sortKey] - $b[$sortKey];
});
Got to agree with #RocketHazmat, array_multsort is a royal pain in the backside. usort is much easier to follow but I thought I'd have a go anyway:
$sortKey = 1;
array_multisort(array_map(function($v) use($sortKey){
return $v[$sortKey];
}, $arr1), $arr1);
It only took 20 minutes... :(
Here's a demo: http://ideone.com/2rZYIz

Get max value from each column of a 2-dimensional array

I have an array within an array, for example:
[
[0, 20, 5],
[5, 0, 15],
[5, 10, 0]
]
I need to get the max number in each column.
The max of [0 , 5 , 5] is 5, so that goes into the result array.
The max of [20, 0, 10] is 20, so that goes into the result array.
The max of [5, 15, 0] is 15, so that goes into the result array.
The final result array must contain [5, 20, 15].
First, the array has to be transposed (flip the rows and columns):
function array_transpose($arr) {
$map_args = array_merge(array(NULL), $arr);
return call_user_func_array('array_map', $map_args);
}
(taken from Is there better way to transpose a PHP 2D array? - read that question for an explanation of how it works)
Then, you can map the max function on the new array:
$maxes = array_map('max', array_transpose($arr));
Example: http://codepad.org/3gPExrhO
Output [I think this is what you meant instead of (5, 15, 20) because you said index 1 should be max of (20, 0, 10)]:
Array
(
[0] => 5
[1] => 20
[2] => 15
)
Without the splat operator, array_map() with max() will return the max value for each row. ([20, 15, 10])
With the splat operator to transpose the data structure, the max value for each column is returned.
Code: (Demo)
$array = [
[0, 20, 5],
[5, 0, 15],
[5, 10, 0]
];
var_export(
array_map('max', ...$array)
);
Output:
array (
0 => 5,
1 => 20,
2 => 15,
)

Sending multidimensional array from jQuery to php

I am passing an array from jQuery to php.
The array is generated from a table with this code:
var stitchChartArray = [];
var row = 0;
// turn stitch chart into array for php
$('#stitchChart').find('tr').each(function (index, obj) {
//first row is table head- "Block #"
if(index != 0){
stitchChartArray.push([]);
var TDs = $(this).children();
$.each(TDs, function (i, o) {
var cellData = [$(this).css('background-color'), $(this).find("img").attr('src')];
stitchChartArray[row].push(cellData);
});
row++;
}
});
In console it looks like this:
[[["rgb(75, 90, 60)", "symbols/177.png"], ["rgb(75, 75, 60)", "symbols/184.png"], ["rgb(75, 90, 60)", "symbols/177.png"], 7 more...], [["rgb(105, 105, 105)", "symbols/163.png"], ["rgb(75, 75, 60)", "symbols/184.png"], ["rgb(75, 90, 60)", "symbols/177.png"], 7 more...], [["rgb(105, 105, 105)", "symbols/163.png"], ["rgb(75, 90, 60)", "symbols/177.png"], ["rgb(75, 75, 60)", "symbols/184.png"], 7 more...], [["rgb(75, 90, 60)", "symbols/177.png"], ["rgb(75, 90, 60)", "symbols/177.png"], ["rgb(98, 119, 57)", "symbols/210.png"], 7 more...], [["rgb(105, 105, 105)", "symbols/163.png"], ["rgb(105, 105, 105)", "symbols/163.png"], ["rgb(150, 150, 195)", "symbols/72.png"], 7 more...], [["rgb(75, 165, 105)", "symbols/187.png"], ["rgb(134, 158, 134)", "symbols/64.png"], ["rgb(165, 180, 180)", "symbols/171.png"], 7 more...], [["rgb(60, 150, 75)", "symbols/189.png"], ["rgb(120, 120, 90)", "symbols/225.png"], ["rgb(143, 163, 89)", "symbols/209.png"], 7 more...]]
It represents each row of a table->each cell of row->[0]rgb value of bg of cell [1]icon in cell.
This jQuery code returns the correct element(and rgb value) from the array:
alert(stitchChartArray[1][1][0]); //row 1,cell 1, first value(rgb)
But when it gets sent to the php script with this:
$.post('makeChartPackage.php', {'stitchChart[]': stitchChartArray }, function(data){
alert(data);
});
The php throws an error:
Cannot use string offset as an array in /Users/tnt/Sites/cross_stitch/makeChartPackage.php on line 33
$stitchChart = $_POST['stitchChart'];
echo $stitchChart[1][1][0]; //line 33
I am assuming I am either constructing the array incorrectly or passing it to the php script incorrectly.
EDIT:
I did this to return the array to jQuery:
$stitchChart = $_POST['stitchChart'];
print_r($stitchChart);
And here was the result:
Array
(
[0] => rgb(75, 90, 60),symbols/177.png,rgb(75, 75, 60),symbols/184.png,rgb(75, 90, 60),symbols/177.png,rgb(98, 119, 57),symbols/210.png,rgb(180, 195, 105),symbols/388.png,rgb(165, 165, 120),symbols/235.png,rgb(75, 75, 60),symbols/184.png,rgb(90, 90, 45),symbols/195.png,rgb(120, 120, 75),symbols/156.png,rgb(105, 105, 105),symbols/163.png
[1] => rgb(105, 105, 105),symbols/163.png,rgb(75, 75, 60),symbols/184.png,rgb(75, 90, 60),symbols/177.png,rgb(75, 90, 60),symbols/177.png,rgb(165, 165, 120),symbols/235.png,rgb(120, 120, 75),symbols/156.png,rgb(75, 90, 60),symbols/177.png,rgb(75, 90, 60),symbols/177.png,rgb(105, 105, 105),symbols/163.png,rgb(120, 120, 90),symbols/225.png
[2] => rgb(105, 105, 105),symbols/163.png,rgb(75, 90, 60),symbols/177.png,rgb(75, 75, 60),symbols/184.png,rgb(75, 90, 60),symbols/177.png,rgb(98, 119, 57),symbols/210.png,rgb(75, 90, 60),symbols/177.png,rgb(75, 75, 60),symbols/184.png,rgb(105, 105, 105),symbols/163.png,rgb(120, 120, 90),symbols/225.png,rgb(105, 105, 105),symbols/163.png
It appears the array is not multidimensional?
$_POST['stitchChart'] in the context you have addressed it there is (effectively) a JSON representation of a multidimensional array, stored as a string. When you treat a string as a multidimensional indexed array in PHP, you will get that error. The first [x] is treated as a "string offset" - i.e. the character at position x - but the next and any subsequent [x] addresses can only be treated as arrays (you cannot get a substring of a single character) and will emit the error you have received.
To access your data as an array in PHP, you need to use json_decode():
$stitchChart = json_decode($_POST['stitchChart'],TRUE);
echo $stitchChart[1][1][0];
EDIT
Because the jQuery data argument seemingly can't deal with multidimensional arrays, you should use Douglas Crockford's JSON-js library and pass the result into data as a string. NB: use json2.js.
Here is how you could do this:
stitchChartArray = JSON.stringify(stitchChartArray);
$.post('makeChartPackage.php', {'stitchChart': stitchChartArray }, function(data){
alert(data);
});
If you use this code, my original PHP suggestion should work as expected.

array_multisort to sort several arrays

I've searched for this but can't seem to find the exact answer. I want to use array_multisort to simultanously sort 3 arrays based on numeric values in 3 of the arrays. Basically I want to make a "standings" table similar to what you'd see for NFL/NHL standings etc. I have 3 arrays, tempIDs (string), tempWins (numeric), tempWinPercentage (numeric). I need all 3 to be sorted at the same time based first on wins, and then if there is a tie, win percentage.
I can't seem to get array_multisort to work with more than just 2 arrays, so maybe I'm misunderstanding the terminology when they say that it can work with "several" arrays. Thank you!
You should have a data array like this:
$data = array(
0 => array(
'tempIDs' => 'something',
'tempWins' => 10,
'tempWinPercentage' => 50,
),
1 => array(
'tempIDs' => 'something else',
'tempWins' => 10,
'tempWinPercentage' => 60,
),
3 => array(
'tempIDs' => 'something more',
'tempWins' => 20,
'tempWinPercentage' => 50,
),
);
Then sort this array using usort($data, 'my_sort_cb')
Your callback method should first compare tempWins, and if they are equal, compare tempWinPercentages:
function my_sort_cb($a, $b) {
if ($a['tempWins'] > $b['tempWins']) return 1;
if ($a['tempWins'] < $b['tempWins']) return -1;
if ($a['tempWinPercentage'] > $b['tempWinPercentage']) return 1;
if ($a['tempWinPercentage'] < $b['tempWinPercentage']) return -1;
return 0;
}
(this can be made shorter)
I can't seem to get array_multisort to
work with more than just 2 arrays, so
maybe I'm misunderstanding the
terminology when they say that it can
work with "several" arrays. Thank you!
I think they mean it can be used for sorting more than two arrays, but the other arrays will be sorted basing on the first one.
In example, executing this code
$a1 = array(12, 23, 34, 45, 45, 34);
$a2 = array(234, 56, 243, 456, 34, 346);
$a3 = array(654, 56, 8, 12, 56, 90);
array_multisort($a1, $a2, $a3);
you will get the arrays sorted as if the would have been defined as
$a1 = array(12, 23, 34, 34, 45, 45);
$a3 = array(654, 56, 8, 90, 56, 12);

Categories