Finding array with highest and lowest number of elements - php

I would like to figure out which array is the biggest and the smallest according to the number of values it contains.
For example:
$array=[
"subarray1"=>[1]
"subarray2"=>[1,2,3,4,5,6,7,8]
"subarray3"=>[1,2,3,4]
];
max_elements($array) returns subarray2 and min_elements($array) returns subarray1
Does PHP have any functions that can select array with most number of elements and the array with the least number elements?

iterate once getting the count, then return the key with array_search using min or max
<?php
function extreme_elements($arr, $min_max){
foreach ($arr as $key => $val)
$arr[$key] = count($val);
return array_search($min_max($arr),$arr);
}
// friendly named wrappers
function max_elements($arr){
return extreme_elements($arr, 'max');
}
function min_elements($arr){
return extreme_elements($arr, 'min');
}
$array=[
"subarray1"=>[1],
"subarray2"=>[1,2,3,4,5,6,7,8],
"subarray3"=>[1,2,3,4]
];
echo max_elements($array); // subarray2
echo min_elements($array); // subarray1

An example of finding the keys for the sub-arrays that contain the least members:
<?php
$array=[
'subarray1'=>[1],
'subarray2'=>[1,2,3,4,5,6,7,8],
'subarray3'=>[1,2,3,4],
'subarray4'=>[3],
];
$counted = array_map('count', $array);
$min_member_count = min($counted);
$mins = array_filter($counted, function($item) use ($min_member_count) {
if($min_member_count == $item) return true;
});
var_export(array_keys($mins));
Output:
array (
0 => 'subarray1',
1 => 'subarray4',
)
Inspired by #Rizier123's comment.

Related

How do I loop through a multidimensional array to retrieve keys where the value is one?

Here is my array: [["STR_License_Driver",1],["STR_License_Truck",0],["STR_License_Pilot",1],["STR_License_Firearm",0],["STR_License_Rifle",0]]
My goal is to make an array or string (unsure of best method) called results where the value of the licenses is 1.
For example: The results should be something like: STR_Licenses_Driver, STR_Licenses_Pilot.
I am currently using PHP Version 7, and Laravel Version 5.5
JSON Decode the $this->license and do the loop.
Whole code:
$licenses = $this->licenses;//This is your posted array string
$result = json_decode($licenses);
$licenses_with_1 = array();
foreach($result as $i){
foreach($i as $key => $value){
if($value == 1){
$licenses_with_1[] = $i[0];
}
}
}
print_r($licenses_with_1);
Result:
Array ( [0] => STR_License_Driver [1] => STR_License_Pilot )
I remember Python on your data structure.
Try my solution:
https://3v4l.org/nrfqZ
$licenses = [["STR_License_Driver",1],["STR_License_Truck",0],["STR_License_Pilot",1],["STR_License_Firearm",0],["STR_License_Rifle",0]];
Map over filtered array having second item equal to 1 to get the license names.
$filterVal = 1;
$licenseNames = array_map(
function ($item) { return $item[0]; },
array_filter(
$licenses,
function ($item) use ($filterVal) { return $item[1] === $filterVal; }
)
);
Then implode array of license names to join by glue string.
echo implode($licenseNames, ', ');

Average from inner array

my task is to calculate average value from an array.
$arrayToTest = [[[1], 1], [[1,3,5,7], 4], [[2,5,4,1,2,3], 2.8],
[[-1,-1,-1,-1,-1], -1], [[4,23,84,12,76,34,-7,-23], 25.375]];
From inner array, so for example [1,3,5,7] and expected value is 4.
I have to use a function, I tried this:
function arrayAverage ($arrayToTest)
{
foreach($arrayToTest as $case)
foreach ($case as $item)
{
$arraySum = array_sum($item);
$arrayCount = array_count_values($item);
$average = $arraySum / $arrayCount;
return $average;
}
}
but it does not work. I feel I'm doing something wrong with calling the inner array.
Comment:
I assume that you wish to calculate the average values of the innermost arrays.
The solution below returns the average of each array - not the average of all arrays. But - of course you easily could calculate the average of all arrays.
Therefore the function arrayAverage(…) returns an array of average values instead of the average value of (only) the last array.
I declared the input array (arrayToTest) explicitely, for the reason that one can better see the array structure (array of arrays and scalars) like this.
Code:
<?php
$arrayToTest = array (
array(
array(1),
1
),
array(
array(1,3,5,7),
4
),
array(
array(2,5,4,1,2,3),
2.8
),
array(
array(-1,-1,-1,-1,-1),
-1
),
array(
array(4,23,84,12,76,34,-7,-23),
25.375
)
);
echo '<pre>'; print_r($arrayToTest); echo '</pre>';
$average = arrayAvarage ($arrayToTest);
echo '<pre>'; print_r($average); echo '</pre>';
function arrayAvarage ($arrayToTest) {
$result = array();
foreach($arrayToTest as $case) {
foreach ($case as $items) {
if (!is_array($items)) continue;
$result[] = array_sum($items) / count($items);
}
}
return $result;
}
?>
Result:
Array
(
[0] => 1
[1] => 4
[2] => 2.8333333333333
[3] => -1
[4] => 25.375
)
if your array contains internal arrays in the index 0, you can do this by:
function arrayAvarage ($arrayToTest)
{
$out_put_arr = array();
foreach($arrayToTest as $case)
{
$arraySum = array_sum($case[0]);
$arrayCount = array_count_values($case[0]);
$avarage = $arraySum / $arrayCount;
$out_put_arr[]= $avarage;
}
return $out_put_arr;
}
so the loop for the main array, each item in the main array will give you array, and int $case[0] = [1,3,5,7] and $case[1] = 4, also you shouldn't return in for loop because this will return the first average only. so you can declare new array to fill with all averages.
function average($array){
return array_sum($array) / count($array);
}
foreach($arrayToTest as $array){
echo "Average: " . average($array[0]);
}
You should look at the first element of the $case array, which is the actual place where the array with values is situated. Note that you can also use the array_sum function.
Also, you should not return just like that, because that will interrupt the function from doing anything more. So, only return when you really want to do that.
As you already have expected values, I see no reason why your function should return those averages again. Instead it could verify the correctness of these expected values, and return the index of the array when that comparison fails.
function arrayAverage ($arrayToTest)
{
foreach($arrayToTest as $index => $case) {
$average = array_sum($case[0]) / count($case[0]);
if ($average !== $case[1]) {
return $index; // not expected value
}
}
return false; // all averages are equal to expected value
}
So, the above function will return FALSE when all averages are as expected. Otherwise it will return the index of the first mismatch.

Count occurrences of a specific value in multidimensional array

Let's say I have a multidimensional array like this:
[
["Thing1", "OtherThing1"],
["Thing1", "OtherThing2"],
["Thing2", "OtherThing3"]
]
How would I be able to count how many times the value "Thing1" occurs in the multidimensional array?
you can use array_search for more information see this http://www.php.net/manual/en/function.array-search.php
this code is sample of this that is in php document sample
<?php
function recursiveArraySearchAll($haystack, $needle, $index = null)
{
$aIt = new RecursiveArrayIterator($haystack);
$it = new RecursiveIteratorIterator($aIt);
$resultkeys;
while($it->valid()) {
if (((isset($index) AND ($it->key() == $index)) OR (!isset($index))) AND (strpos($it->current(), $needle)!==false)) { //$it->current() == $needle
$resultkeys[]=$aIt->key(); //return $aIt->key();
}
$it->next();
}
return $resultkeys; // return all finding in an array
} ;
?>
If needle is found in haystack more than once, the first matching key is returned. To return the keys for all matching values, use array_keys() with the optional search_value parameter instead.
http://www.php.net/manual/en/function.array-keys.php
Try this :
$arr =array(
array("Thing1","OtherThing1"),
array("Thing1","OtherThing2"),
array("Thing2","OtherThing3")
);
echo "<pre>";
$res = array_count_values(call_user_func_array('array_merge', $arr));
echo $res['Thing1'];
Output :
Array
(
[Thing1] => 2
[OtherThing1] => 1
[OtherThing2] => 1
[Thing2] => 1
[OtherThing3] => 1
)
It gives the occurrence of each value. ie : Thing1 occurs 2 times.
EDIT : As per OP's comment : "Which array do you mean resulting array?" - The input array. So for example this would be the input array: array(array(1,1),array(2,1),array(3,2)) , I only want it to count the first values (1,2,3) not the second values (1,1,2) – gdscei 7 mins ago
$arr =array(
array("Thing1","OtherThing1"),
array("Thing1","OtherThing2"),
array("Thing2","OtherThing3")
);
$res = array_count_values(array_map(function($a){return $a[0];}, $arr));
echo $res['Thing1'];
function showCount($arr, $needle, $count=0)
{
// Check if $arr is array. Thx to Waygood
if(!is_array($arr)) return false;
foreach($arr as $k=>$v)
{
// if item is array do recursion
if(is_array($v))
{
$count = showCount($v, $needle, $count);
}
elseif($v == $needle){
$count++;
}
}
return $count;
}
Using in_array can help:
$cont = 0;
//for each array inside the multidimensional one
foreach($multidimensional as $m){
if(in_array('Thing1', $m)){
$cont++;
}
}
echo $cont;
For more info: http://php.net/manual/en/function.in-array.php
try this
$arr =array(
array("Thing1","OtherThing1"),
array("Thing1","OtherThing2"),
array("Thing2","OtherThing3")
);
$abc=array_count_values(call_user_func_array('array_merge', $arr));
echo $abc[Thing1];
$count = 0;
foreach($array as $key => $value)
{
if(in_array("Thing1", $value)) $count++;
}
If you prefer code brevity zero global scope pollution, you can count every value and access the one count that you do want:
echo array_count_values(array_merge(...$array))['Thing1'] ?? 0;
If you don't want to bother counting values where the count will never be needed, then you can visit leafnodes with array_walk_recursive() and +1 everytime the target value is encountered.
$thing1Count = 0;
array_walk_recursive($array, function($v) use(&$thing1Count) { $thing1Count += ($v === 'Thing1'); });
echo $thing1Count;
Both snippets return 2. Here's a Demo.

Is there a way to loop through a multidimensional array without knowing it's depth?

So far, if I have to loop through a multidimensional array, I use a foreach loop for each dimension.
e.g for two dimensions
foreach($array as $key=>$value)
{
foreach($value as $k2=>$v2)
{
echo
}
}
What do I do when I don't know the depth of the array? ie the depth is variable.
The only thing I can think of is to code a whole stack of loops and to break the loop if the next value is not an array.This seems a little silly.
Is there a better way?
Yes, you can use recursion. Here's an example where you output all the elements in an array:
function printAll($a) {
if (!is_array($a)) {
echo $a, ' ';
return;
}
foreach($a as $v) {
printAll($v);
}
}
$array = array('hello',
array('world',
'!',
array('whats'),
'up'),
array('?'));
printAll($array);
What you should always remember when doing recursion is that you need a base case where you won't go any deeper.
I like to check for the base case before continuing the function. That's a common idiom, but is not strictly necessary. You can just as well check in the foreach loop if you should output or do a recursive call, but I often find the code to be harder to maintain that way.
The "distance" between your current input and the base case is called a variant and is an integer. The variant should be strictly decreasing in every recursive call. The variant in the previous example is the depth of $a. If you don't think about the variant you risk ending up with infinite recursions and eventually the script will die due to a stack overflow. It's not uncommon to document exactly what the variant is in a comment before recursive functions.
You can do the below function for loop-through-a-multidimensional-array-without-knowing-its-depth
// recursive function loop through the dimensional array
function loop($array){
//loop each row of array
foreach($array as $key => $value)
{
//if the value is array, it will do the recursive
if(is_array($value) ) $array[$key] = loop($array[$key]);
if(!is_array($value))
{
// you can do your algorithm here
// example:
$array[$key] = (string) $value; // cast value to string data type
}
}
return $array;
}
by using above function, it will go through each of the multi dimensional array, below is the sample array you could pass to loop function :
//array sample to pass to loop() function
$data = [
'invoice' => [
'bill_information' => [
'price' => 200.00,
'quantity' => 5
],
'price_per_quantity' => 50.00
],
'user_id' => 20
];
// then you can pass it like this :
$result = loop($data);
var_dump($result);
//it will convert all the value to string for this example purpose
You can use recursion for this problem:
Here is one example
$array = array(1 => array(1 => "a", 2 => array(1 => "b", 2 => "c", 3 => array(1 => "final value"))));
//print_r($array);
printAllValues($array);
function printAllValues($arr) {
if(!is_array($arr)) {
echo '<br />' . $arr;
return;
}
foreach($arr as $k => $v) {
printAllValues($v);
}
}
It will use recursion to loop through array
It will print like
a
b
c
final value
Simple function inside array_walk_recursive to show the level of nesting and the keys and values:
array_walk_recursive($array, function($v, $k) {
static $l = 0;
echo "Level " . $l++ . ": $k => $v\n";
});
Another one showing use with a reference to get a result:
array_walk_recursive($array, function($v) use(&$result) {
$result[] = $v;
});
Based on previous recursion examples, here is a function that keeps an array of the path of keys a value is under, in case you need to know how you got there:
function recurse($a,$keys=array())
{
if (!is_array($a))
{
echo implode("-", $keys)." => $a <br>";
return;
}
foreach($a as $k=>$v)
{
$newkeys = array_merge($keys,array($k));
recurse($v,$newkeys);
}
}
recurse($array);

PHP: Getting to a key in mulitdimensional array?

I have an array like
$myArray =array
(
"0"=>array("dogs",98),
"1"=>array("cats",56),
"2"=>array("buffaloes",78)
)
How can I get a key by providing a value?
e.g. if i search for "buffaloes" array_search may return "2".
Thanks
$myArray =array
(
"0"=>array("dogs",98),
"1"=>array("cats",56),
"2"=>array("buffaloes",78)
);
function findInArray($term, $array) {
foreach($array as $key => $val) {
if(in_array($term, $val, true)) {
return $key;
}
}
}
echo findInArray('buffaloes', $myArray); // 2
echo findInArray(78, $myArray); // 2
function asearch($key, $myArray) {
for ($i = 0; $i < sizeof($myArray); $i++) {
if ($myArray[$i][0] == $key) {
return $i;
}
}
return -1; # no match
}
Though, you'd probably want to restructure your array to:
$myarray = array(
'dogs' => 98,
'cats' => 56,
'buffaloes' => 78
);
And just do:
$myArray['buffaloes']; # 78
The only way you can do it is to iterate over every item and preform a Linear Search
$i = -1;
foreach ($myArray as $key => $item){
if ( $item[0] == 'buffaloes' ){
$i = $key;
break;
}
}
//$i now holds the key, or -1 if it doesn't exist
As you can see, it is really really inefficient, as if your array has 20,000 items and 'buffaloes' is the last item, you have to make 20,000 comparisons.
In other words, you need to redesign your data structures so that you can look something up using the key, for example a better way may be to rearrange your array so that you have the string you are searching for as the key, for example:
$myArray['buffaloes'] = 76;
Which is much much faster, as it uses a better data structure so that it only has to at most n log n comparisons (where n is the number of items in the array). This is because an array is in fact an ordered map.
Another option, if you know the exact value of the value you are searching for is to use array_search
I never heard of built in function. If you want something more general then above solutions you shold write your own function and use recursion. maybe array_walk_recursive would be helpful
You can loop over each elements of the array, testing if the first element of each entry is equal to "buffaloes".
For instance :
foreach ($myArray as $key => $value) {
if ($value[0] == "buffaloes") {
echo "The key is : $key";
}
}
Will get you :
The key is : 2
Another idea (more funny ?), if you want to whole entry, might be to work with array_filter and a callback function that returns true for the "bufalloes" entry :
function my_func($val) {
return $val[0] == "buffaloes";
}
$element = array_filter($myArray, 'my_func');
var_dump($element);
Will get you :
array
2 =>
array
0 => string 'buffaloes' (length=9)
1 => int 78
And
var_dump(key($element));
Gves you the 2 you wanted.

Categories