Find shortest array count in multidimensional array - php

I have a multidimensional array:
$arr = array(
array('lions', 'tigers', 'bears'), // count = 3
array('dogs', 'cats'), // count = 2
array('horses', 'pigs', 'cattle', 'sheep', 'chickens') // count = 5
);
I want to return the array with the lowest count (I don't need to know the count, just need the array that HAS the lowest count). In this case, array('dogs', 'cats')
Right now I have:
$lowest = null;
foreach($nodePath as $arr)
{
$lowest = count($arr) < count($lowest) || $lowest == null ? $arr : $lowest;
}
This works but I'm wondering if I missed a more contained solution, perhaps using array_map, array_walk or a similar function.

Use array_map() with count as a callback to get the number of elements in each array, min() to get the smallest value. Then, to get the key of the smallest array - use array_flip() to flip the arrays keys and values, and access the $minth index. Now you can use the key to get the array you need:
$counts = array_map('count', $arr);
$min = min($counts);
$key = array_flip($counts)[$min];
$smallest_arr = $arr[$key];
Demo

Map your array to another array with counts of each child array. Get the key of the minimum value in this new array. Smallest array has the key of the minimum value:
$count = array_map('count', $arr);
$min = array_keys($count , min($count))[0];
var_dump($arr[$min]); // Array ( [0] => dogs [1] => cats )
Eval.in

Related

PHP - Get first and last key and value from array

From a given array (eg: $_SERVER), I need to get the first and last key and value. I was trying use array_shift to get first value and key but what I get is value.
Here is the $_SERVER array:
print_r($_SERVER, true))
And I tried with:
echo array_shift($_SERVER);
With PHP >= 7.3 you can get it fast, without modification of the array and without creating array copies:
$first_key = array_key_first($_SERVER);
$first_value = $_SERVER[$first_key];
$last_key = array_key_last($_SERVER);
$last_value = $_SERVER[$last_key];
See array_key_first and array_key_last.
It's not clear if you want the value, or the key. This is about as efficient as it gets, if memory usage is important.
If you want the key, use array_keys. If you want the value, just refer to it with the key you got from array_keys.
$count = count($_SERVER);
if ($count > 0) {
$keys = array_keys($_SERVER);
$firstKey = $keys[0];
$lastKey = $keys[$count - 1];
$firstValue = $array[$firstKey];
$lastValue = $array[$lastKey];
}
You can't use $count - 1 or 0 to get the first or last value in keyed arrays.
You can do a foreach loop, and break out after the first one:
foreach ( $_SERVER as $key => $value ) {
//Do stuff with $key and $value
break;
}
Plenty of other methods here. You can pick and choose your favorite flavor there.
Separate out keys and values in separate arrays, and extract first and last from them:
// Get all the keys in the array
$all_keys = array_keys($_SERVER);
// Get all the values in the array
$all_values = array_values($_SERVER);
// first key and value
$first_key = array_shift($all_keys);
$first_value = array_shift($all_values);
// last key and value (we dont care about the pointer for the temp created arrays)
$last_key = end($all_keys);
$last_value = end($all_values);
/* you can use reset function after end function call
if you worry about the pointer */
What about this:
$server = $_SERVER;
echo array_shift(array_values($server));
echo array_shift(array_keys($server));
reversed:
$reversed = array_reverse($server);
echo array_shift(array_values($reversed));
echo array_shift(array_keys($reversed));
I think array_slice() will do the trick for you.
<?php
$a = array_slice($_SERVER, 0, 1);
$b = array_slice($_SERVER, -1, 1, true);
//print_r($_SERVER);
print_r($a);
print_r($b);
?>
OUTPUT
Array ( [TERM] => xterm )
Array ( [argc] => 1 )
DEMO: https://3v4l.org/GhoFm

PHP removing a specific array from a multidimensional array

I have a multidimensional array in PHP where I need to remove one array based on the value of an item in one of the arrays:
Example Array
array(
"0"=>array("0"=>"joe", "1"=>"2018-07-18 09:00:00"),
"1"=>array("0"=>"tom", "1"=>"2018-07-17 09:00:00"),
"2"=>array("0"=>"joe", "1"=>"2018-07-14 09:00:00")
)
I know that I want to remove the array that contains joe in key 0, but I only want to remove the array that contains joe with the most current date in key1. The following output is what I'm trying to accomplish:
array(
"0"=>array("0"=>"tom", "1"=>"2018-07-17 09:00:00"),
"1"=>array("0"=>"joe", "1"=>"2018-07-14 09:00:00")
)
Is there a simple way to do this in PHP aside from looping through each array?
Here is a non looping method that uses array_intersect and array_column to find the "Joe's" and then deletes the maximum array_key since I first sort the array on dates.
usort($arr, function($a, $b) {
return $a[1] <=> $b[1];
}); // This returns the array sorted by date
// Array_column grabs all the names in the array to a single array.
// Array_intersect matches it to the name "Joe" and returns the names and keys of "Joe"
$joes = array_intersect(array_column($arr, 0), ["joe"]);
// Array_keys grabs the keys from the array as values
// Max finds the maximum value (key)
$current = max(array_keys($joes));
unset($arr[$current]);
var_dump($arr);
https://3v4l.org/mah6K
Edit forgot to add the array_values() if you want to reset the keys in the array.
Just add $arr = array_values($arr); after the unset.
I would go about it like this:
<?php
$foo = array(
"0"=>array("0"=>"joe", "1"=>"2018-07-18 09:00:00"),
"1"=>array("0"=>"tom", "1"=>"2018-07-17 09:00:00"),
"2"=>array("0"=>"joe", "1"=>"2018-07-14 09:00:00")
);
$tmp = [];
foreach($foo as $k => $v) {
if ($v[0] === 'joe') {
$tmp[$v[1]] = $k;
}
}
if (!empty($tmp)) {
sort($tmp); //think that is sane with date format?
unset($foo[reset($tmp)]);
}
var_dump($foo);
Not sure if you don't want to loop on principal or what... I tend to go for readability. Find all occurrences of joe. Sort on date. Remove the most recent by key.

Get the highest number from an array

I have the following array:
Array ( [0] => 80 ) Array ( [0] => 20 ) Array ( [0] => 90 )
Code:
$percentage_query = $this->Common_model->getTableData('prop_payment_percentage', array('list_id' => $id));
$percentage_result = $percentage_query->result_array();
foreach ($percentage_result as $ptime) {
$percentage_start_date = $percentage_query->row()->start_date;
$percentage_end_date = $percentage_query->row()->end_date;
$percentage_percentage = $percentage_query->row()->percentage;
//Days between start date and end date -> seasonal price
$start_time = $ptime['start_date'];
$end_time = $ptime['end_date'];
$hightest_percentage = $ptime['percentage']; // this is the array 802090
//help me echo 90
}
How should i return the Value 90? As It is the highest number which i would like to return into a $variable
Unless the array is sorted, that's the best you're going to get. If it is sorted, just take the first and last elements.
Of course, if it's not sorted, then sorting first and grabbing the first and last is guaranteed to be less efficient than just looping through once. Even the best sorting algorithms have to look at each element more than once (an average of O(log N) times for each element. That's O(N*Log N) total. A simple scan once through is only O(N).
If you are wanting quick access to the largest element in a data structure, take a look at heaps for an efficient way to keep objects in some sort of order.
sort() - sort arrays in ascending order
rsort() - sort arrays in descending order
asort() - sort associative arrays in ascending order, according to the value
ksort() - sort associative arrays in ascending order, according to the key
arsort() - sort associative arrays in descending order, according to the value
krsort() - sort associative arrays in descending order, according to the key
if we use ascending order then to access last element we have to count array size and arr[last_position] gives highest order
But by sorting array in descending order there is no need to count array size. Just access first number and you will get highest number
if you have an array containing your arrays, you can do it like this:
$masterArray = array(
array(80),
array(20),
array(90),
);
$highestValue = 0;
foreach($masterArray as $arr){
$highestValue = $arr[0] > $highestValue ? $arr[0] : $highestValue;
}
echo $highestValue; //echo 90;
Here is the example If you have 3 array or variables.
$a1 = Array ( "0" => 80 );
$a2 = Array ( "0" => 20 );
$a3 = Array ( "0" => 90 );
$a4 = array_merge($a1,$a2);
$a5 = array_merge($a4,$a3);
echo '<pre>';
print_r(max($a5));
You don't need to loop. Merge the three arrays and then use max();
$array = array_merge(array(80),array(20),array(20));
$max = max($array);
<?
$a=array(0 => 1300 );
$b=array(0 => 500 );
$c=array(0 => 1220 );
$MaxValue=0;
if($a[0]>$b[0])
{
$MaxValue=$a[0];
if($b[0]>$MaxValue)
{
$MaxValue=$b[0];
}
else
{
if($c[0]>$MaxValue)
{$MaxValue=$c[0];}
}
}
else
{
if($b[0]>$c[0])
{
$MaxValue=$b[0];
}
else
{
$MaxValue=$c[0];
}
}
echo $MaxValue;
?>
The easiest way would be to use the standard code function from php:
$array = array(0 => 80, 1 => 20, 2 => 90);
$variable = max($array);
See also the documentation at http://php.net/manual/en/function.max.php
update: this function takes more than just an array of integers. All these are valid and return 3 as expected:
$a1 = array(1);
$a2 = array(2);
$a3 = array(3);
$i1 = 1;
$i2 = 2;
$i3 = 3;
$arr1 = array($a1, $a2, $a3);
$arr2 = array($i1, $i2, $i3);
echo max($a1, $a2, $a3), "\n"; // 3
echo max($i1, $i2, $i3), "\n"; // 3
echo max($arr1), "\n"; // 3
echo max($arr2), "\n"; // 3
It does not matter what keys are used in the arrays.
update 2: if you really need to work from the value 802090 and you can be sure that the values are always 2-digit percentages, you could also use the str_split function (and then again the max function):
$hightest_percentage = 802090;
$hpr = str_split($hightest_percentage, 2); // array ( 80, 20, 90 );
print_r(max($hpr)); // 90

How to deal with an array of equal values and max function?

In PHP, max() returns the highest value in an array or the greatest value among inputs. If we have two or more equally greatest values, how to deal with that situation?
eg
$arr = array("a"=>1,"b"=>10, "c"=>10);
now, what should max($arr), return. Ideally it returns the first encountered highest value, b. What if I want both b and c as result?
If you have the highest value in that array (that is, what max() returns), you can just search for all occurrences of that value in the array:
$arrOfKeys = array_keys($arr, max($arr));
max() returns the maximum value, not the array key it is associated with. It will simply return (int) 10 in the example you give.
If you want a list of the keys that have the maximum value you could do something like this:
$max = max($array);
$maxKeys = array();
foreach ($array as $key => $val) {
if ($val == $max) {
$maxKeys[] = $key;
}
}
print_r($maxKeys);
/*
Array
(
[0] => b
[1] => c
)
*/

Efficient algorithm for detecting matches

I'm looking for an efficient algorithm for detecting equal values in an array of integers N size. It must return the indices of the matches.
Alas, I can't think of anything more clever then brute force with two loops.
Any help will be appreciated.
Thanks!
You could intersect the array. This finds all the values of array2 that are in array1
$array1 = array("a" => "green", "b" => "brown", "c" => "blue", "red");
$array2 = array("a" => "green", "yellow", "red");
$result_array = array_intersect_assoc($array1, $array2);
print_r($result_array);
Would return
Array
(
[a] => green
)
It returns an array with all of the keys and values of the matches. Basically you can provide an infinite number of arguments to the array_insert_assoc:
array_intersect_assoc($base_array, $arr1, $arr2 ...);
It will search $base_array for the values that are in all the subsequent arrays. That means that the key and value will be taken from the $base_array
You could also compare the keys by using:
array_intersect_keys($base_array, $arr1, $arr2, $arr3);
These loops are O(N^2). Is N big? If so, can you sort the array O(NlogN), then scan it O(N)? ... or am I missing something?
You can use a set to hold the recent values. For example,
results = empty list
set = empty set
foreach key, val in array:
if val is not in set: add val to set
else: add key to results
return results
Each look up of set is O(1), so this algo will results in O(n) instead of O(n^2) if nested-loop is used.
In case you want to keep track of multi-occurence like this array 1, 2, 3, 3, 2, 1 you can use a hash table with key is the value and value (of the corresponding key in table) is the list of indices. The result for the given array will look lik {1:0, 5; 2: 1, 4; 3: 2, 3}.
results = empty hashtable
for each key, val in array:
if val is not in results:
results[val] = new list()
results[val].append(key)
return results
Perhaps this?
$arr = array_map('unserialize', array_unique(array_map('serialize', $arr)));
From the question: How to remove duplicated 2-dimension array in PHP?
if ($arr !== array_map('unserialize', array_unique(array_map('serialize', $arr))))
{
// found duplicates
}
You don't have to go through all the array again for each element. Only test an element with the subsequent element in the array:
$array = /* huge array */;
$size = count($array);
for($i = 0; $i < $size; $i++)
{
for($j = $i + 1; $j < $size; $j++) // only test with the elements after $i
{
if($array[$i] == $array[$j])
return true; // found a duplicate
}
return false; // found no duplicate
}
That's the most efficient way I can think of. Adapt it to your need as you will.
If one of your arrays is reasonably static (that is you are comparing to the same array several times ) you could invert it.
That is set up another array which is keyed by value and returns the index into the real array.
$invert = array();
foreach ($cmptoarray as $ix => $ival) {
$invert[$ival] = $ix;
}
Then you simply need an if ( isset($invert[$compfrmarray[$i]) ) .... to check the number.
Note: this is only worth doing if you compare against the same array several times!
Just use an associative array mapping a value to its index:
foreach($array1 as $index => $value) {
$aa[$value] = $index;
}
foreach($array2 as $index => $value) {
if(isset($aa[$value])) {
echo 'Duplicate: . Index 1: '.$aa[$value].' Index 2: '.$index.'.';
}
}

Categories