This works but, is it reliable? Will it always work since the MAINarray is containing ANOTHERarray which contains 2 values and min should work in MAINarray and find lowest value in its subarays.
$a[0]=array(0=>522,1=>'Truck');
$a[1]=array(0=>230,1=>'Bear');
$a[2]=array(0=>13,1=>'Feather');
$a[3]=array(0=>40,1=>'Rabit');
$z=min($a);$y=max($a);
echo "The easiest is ".$z[1]." with only ".$z[0]." pounds!<br>";
echo "The heaviest is ".$y[1]." with ".$y[0]." pounds!";
What you say?
Yes, it is reliable. It's safe to assume that min(array(1, 2, ..., n)) is equivalent to min(1, 2, ..., n), and the documentation specifically covers how min compares multiple arrays:
// With multiple arrays, min compares from left to right
// so in our example: 2 == 2, but 4 < 5
$val = min(array(2, 4, 8), array(2, 5, 1)); // array(2, 4, 8)
My understanding of how min works with your type of input is:
Only consider the arrays with the fewest number of items.
Compare the first elements
If there is a tie, compare the next element of each array. Repeat step.
e.g.:
array(
array(1, "A"),
array(2), // min
)
array(
array(1, "A"), // min
array(2, "A"),
)
array(
array(1, "Z"),
array(1, "A"), // min
)
I don't have a source for that information, but it's how I remember it working.
I’m not sure if this always works. In case of doubt just implement the function yourself:
function extremes($array, $key=0) {
if (count($array) === 0) return null;
$min = $max = null;
foreach ($array as &$val) {
if (!isset($val[$key])) continue;
if ($min > $val[$key]) $min = $val[$key];
else if ($max < $val[$key]) $max = $val[$key];
}
return array($min, $max);
}
$a = array(array(522, 'Truck'), array(230, 'Bear'), array(13, 'Feather'), array(40, 'Rabit'));
list($z, $y) = extremes($a);
The only evidence I could find to say it was intended to be able to use an array of arrays to compare is this bug report to improve the php docs. http://bugs.php.net/bug.php?id=50607
Although, it's quite unlikely for them to remove this functionality because of the way it has to compare arrays already by going into them recursively. The arguments list itself when using the function normally would be an array because there is no finite number of arguments.
Related
I am trying to figure out how to count a number that I pull from query string and push each into an array. so if the number is 3, I want to push 1, 2 and 3 as separate numbers into the array. The below code does not work:
$number = $_GET['tics'];
$items = array();
for($numbers = 0; $numbers<$number; $numbers++) {
$items[] = $numbers;
}
var_dump shows an empty array with this code. any idea how to make this work?
I want the key to be "numbers" and the values to be 1, 2, 3 etc..
I am sure this is explained many times already on stack, but when searching I found only examples that was way to advanced for someone like me
you can use range()
Returns an array of elements from start to end, inclusive.
$number = (int) $_GET['tics'];
$items = range(1, $number);
You can use http://php.net/manual/en/function.range.php to generate a list of numbers from min to max.
<?php
$number = 5;
// Do validation on $number before passing it to range.
$result = range(1, $number);
print_r($result);
For starters, your loop is incorrect.
If you pass $number = 3
for ($numbers = 0; $numbers < $number; $numbers++) {
Will give you 0, 1, 2. You need to change it to the following:
for ($numbers = 1; $numbers <= $number; $numbers++) {
This will give you 1, 2, 3.
Anyway, entertaining another idea here, if range() as mentioned by the other answers is not what you require.
I want the key to be "numbers" and the values to be 1, 2, 3 etc..
It's not exactly clear what you mean by this, but I'm guessing you might want the array keys to be the value of $numbers? In which case, you can modify your code as follows:
$number = (int)$_GET['tics'];
$items = array();
for ($numbers = 1; $numbers <= $number; $numbers++) {
$items[$numbers] = $numbers;
}
Your code should somewhat work as intended anyway (the numbers will be incorrect). The reason it doesn't is probably that $_GET['tics'] has no value. Ensure that you do indeed have tics in the $_GET array, and that you aren't actually POSTing (in which case you need $_POST['tics'] instead).
If you change $_GET in your code to $_POST and it still doesn't work, then tics is either not set or does not have a value greater than 0.
$arr = array(
1, 1, 2, 3, 4
);
How to find out the pair from this array ?
Keep in mind that the pair from array could be any number (1,2,4,3,2) or (3,3,1,2,4); I just give an random example above.
if there is a pair in array
echo "The pair number is 1";
All of my methods will return the desired result as long as there IS a duplicate. It is also assumed because of your sample input, that there is only 1 duplicate in the array. The difference between my methods (and the other answers on this page) will be milliseconds at most for your input size. Because your users will not be able to distinguish between any of the correct methods on this page, I will suggest that the method that you implement should be determined by "readability","simplicity", and/or "brevity". There are many coders who always default to for/foreach/while loops. There are others who always defer to functional iterators. Your choice will probably just come to down to "your coding style".
Input:
$arr=[1,1,2,3,4];
Method #1: array_count_values(), arsort(), key()
$result=array_count_values($arr);
arsort($result); // this doesn't return an array, so cannot be nested
echo key($result);
// if no duplicate, this will return the first value from the input array
Explanation: generate new array of value occurrences, sort new array by occurrences from highest to lowest, return the key.
Method #2: array_count_values(), array_filter(), key()
echo key(array_filter(array_count_values($arr),function($v){return $v!=1;}));
// if no duplicate, this will return null
Explanation: generate the array of value occurrences, filter out the 1's, return the lone key.
Method #3: array_unique(), array_diff_key(), current()
echo current(array_diff_key($arr,array_unique($arr)));
// if no duplicate, this will return false
Explanation: remove duplicates and preserve the keys, find element that went missing, return the lone value.
Further consideration after reading: https://www.exakat.io/avoid-array_unique/ and the accepted answer from array_unique vs array_flip I have a new favorite 2-function one-liner...
Method #4: array_count_values(), array_flip()
echo array_flip(array_count_values($arr))[2];
// if no duplicate, this will show a notice because it is trying to access a non-existent element
// you can use a suppressor '#' like this:
// echo #array_flip(array_count_values($arr))[2];
// this will return null on no duplicate
Explanation: count the occurrences (which makes keys of the values), swap the keys and values (creating a 2-element array), access the 2 key without a function call. Quick-smart!
If you wanted to implement Method #4, you can write something like this:(demo)
$dupe=#array_flip(array_count_values($arr))[2];
if($dupe!==null){
echo "The pair number is $dupe";
}else{
echo "There were no pairs";
}
There will be many ways to achieve your desired result as you can see from all of the answers, but I'll stop here.
First sort your array, then use foreach loop and if current and next are equal and not echo this item before this time, echo item is pair.
$arr = array(
1, 3, 1, 2, 2, 2, 3, 4
);
sort($arr);
$last_number = null;
foreach($arr as $key => $item) {
if(array_key_exists($key + 1, $arr)) {
if($item === $arr[$key + 1]) {
if($last_number !== $item) {//prevent duplicate echo pair of one item
echo 'The pair number is ' . $item;
$last_number = $item;
}
}
}
}
Use built-in array_count_values. Then iterate over results and check if count is greater than 1.
$arr = array(
1, 1, 2, 3, 4
);
$values = array_count_values($arr);
foreach ($values as $key => $value) {
if ($value > 1) {
echo 'Pair: ' . $key;
// break, if you need to show first pair only
// break;
}
}
You can first count all the values in the array, then for each distinct value check if it occurs twice in the array.
<?php
$array = array(1, 1, 2, 3, 4);
$vars = array_count_values($array);
foreach($vars as $key => $var) {
if($var == 2) {
echo "The pair number is " . $key . "<br>";
}
}
?>
First sort the array, then check if there are two numbers on consecutive indexes with the same value.
This is the most efficient solution: sorting is done in O(n log n) time1 and doing the checking takes O(n) time. Overall, you'll have the answer in O(n log n) time. Naive approaches will use O(n2) time.
If you don't want to modify the original array, do all of the above on a copy.
function hasEqualPair($arr) {
sort($arr);
$l = count($arr);
for ($i = 1; $i < $l; ++$i) {
if ($arr[$i] === $arr[$i - 1]) {
return true;
}
}
return false;
}
var_dump(hasEqualPair(array(1, 2, 4, 3, 2))); // true
var_dump(hasEqualPair(array(1, 1, 2, 3, 4))); // true
var_dump(hasEqualPair(array(3, 3, 1, 2, 4))); // true
var_dump(hasEqualPair(array(3, 5, 1, 2, 4))); // false
Try it online!
Of course, if you want to know what the pair is, just change return true in the above function to return $arr[$i]. You then might want to change the function name to getEqualPair as well.
1 The sort function in PHP uses Quicksort. It is possible to make that always run in O(n log n) time, but the implementation in PHP probably has an average running time of O(n log n), with worst case running time still O(n2).
$arr = array(
1, 1, 2, 3, 4
);
echo "<pre>";
$vals = array_count_values($arr);
foreach ($vals as $key => $value) {
if($value%2==0){
echo "The pair number is ".$key."<br>";
}else{
echo "The not pair number is ".$key."<br>";
}
}
I have an array in PHP with repeating numbers and I would like to find the most frequent but only when there is only one of that.
while (count(array_count_values($arr)) > 1) {
$minim = min(array_count_values($arr));
while ($minim == min(array_count_values($arr))) {
unset($arr[array_search(array_search(min(array_count_values($arr)), array_count_values($idList)), $arr)]);
$arr = array_splice($arr, 0, 1);
}
}
In my code the first while runs until I have only one number (multiple times) in the array and with the second one I delete the less frequent numbers.
My problem is the I get this error for my second min(): "Array must contain at least one element".
I have an array in PHP with repeating numbers and I would like to find the most frequent but only when there is only one of that.
Your approach seems rather complicated.
Here's how I'd do that:
$numbers = [1, 6, 5, 6, 2, 1, 6, 7, 8]; // positive test case
//$numbers = [1, 6, 5, 6, 2, 1, 6, 7, 8, 1]; // negative test case
$count = array_count_values($numbers); // get count of occurrence for each number
arsort($count); // sort by occurrence, descending
$first = key($count); // get key of first element, because that is the/one
// of the highest number(s)
$count_first = current($count); // get occurrence for first array value
$count_second = next($count); // get occurrence for second array value
if($count_first != $count_second) { // did they occur in different frequencies?
echo $first . ' occurred most in input array.';
}
else {
echo 'input array contained multiple values with highest occurrence.';
}
You could probably perform an array_reduce on the counts to find the max, but because array_reduce does not give you access to the iterable's key, you'd have to perform additional transformation.
Instead, I would recommend you build your own MaxHeap by extending from SplMaxHeap
class MaxHeap extends SplMaxHeap {
public function compare($a, $b) {
if (current($a) < current($b))
return -1;
elseif (current($a) > current($b))
return 1;
else
return 0;
}
}
Then we can use it as such – the answer says [ 7 => 4 ] which means: 7 is the most common number, appearing 4 times
$heap = new MaxHeap();
foreach (array_count_values($numbers) as $n => $count)
$heap->insert([$n => $count]);
print_r($heap->top());
// [ 7 => 4 ]
printf("%d is the most common number, appearing %d times",
key($heap->top()),
current($heap->top())
);
// 7 is the most common number, appearing 4 times
complete script
$numbers = [0, 1, 1, 1, 2, 3, 4, 4, 5, 6, 7, 7, 7, 7, 8, 8, 9];
class MaxHeap extends SplMaxHeap {
public function compare($a, $b) {
if (current($a) < current($b))
return -1;
elseif (current($a) > current($b))
return 1;
else
return 0;
}
}
$heap = new MaxHeap();
foreach (array_count_values($numbers) as $n => $count)
$heap->insert([$n => $count]);
printf("%d is the most common number, appearing %d times",
key($heap->top()),
current($heap->top())
);
revision history
I was unaware of PHP's native array_count_values function. I removed the more complex array_reduce in favor of this super specialised function. Thanks, #CBroe.
How to quickly remove elements in an array that are < 5 apart from each other quickly.
example:
array(1, 3, 5, 8, 11, 15);
needs to return the following cause they are more than 5 if you calculate the difference:
array(1, 8, 15);
This seems like it should be a built-in function in php for this. But I'm baffled.
There's nothing built-in for this, but it's a pretty easy thing to accomplish.
First, sort your array, unless it's already sorted.
sort($your_array);
Initialize your result array with the first element, and then iterate the array. Each time you get to a value at least 5 greater than the previous value, add it to the result and reset the previous value to that value.
$result[] = $previous = reset($your_array);
foreach ($your_array as $value) {
if ($value - $previous >= 5) {
$result[] = $previous = $value;
}
}
I have 2 arrays to compare and find if there is at least a single value in common.
This works just fine:
$arr1 = array(1, 2, 3, 4, 5);
$arr2 = array(2, 3, 4, 5, 6);
if (array_intersect($arr1, $arr2)) {
// good, at least one match found
}
However, the question is performance. It doesn't make sense to continue looping thru the arrays after the first match was found. Is there a native PHP function or a useful snippet to achieve this?
Will a combination of foreach() and in_array() do the trick?
How about this?
foreach ($arr1 as $key => $val) {
if (in_array($val, $arr2)){
// do something, maybe return so you wouldn't need break
break;
}
}
Just compare the first value?
$arr1 = array(1, 2, 3, 4, 5);
$arr2 = array(2, 3, 4, 5, 6);
if (array_intersect($arr1, $arr2)[0]) {
// good, at least one match found
}