Related
I have an array [4,3,5,5,7,6] and I want to loop through the sorted one and subtract the highest value from the preceding value, then subtract the remainder from the value behind it and so on, then in the end, I need one final value that comes when the loop is completed.
For example
Above array will be sorted like
Array
(
[0] => 3
[1] => 4
[2] => 5
[3] => 5
[4] => 6
[5] => 7
)
Now I want to find the difference between arr[5] and arr[4], the result will be 1, then subtract the result from arr[3] and so on till the loop is completed
This is what I tried but it doesn't seem to work
for ($i = count($a)-1; $i >0; $i--){
echo $result = $a[$i] - $a[$i-1];
echo "<br />";
if($result > 0) {
if($result > $a[$i-2]) {
echo $result = $result - $a[$i-2];
} else {
}
}
I think there is a more simple and fast way to achieve this:
$array = [4, 3, 5, 5, 7, 6];
rsort($array);
$result = $array[0] - $array[1];
for($i = 2, $count = count($array); $i < $count; $i++){
$result = $array[$i] - $result;
}
print($result);
output:
0
Do you wish this way?
$a = [1,1,1,3,1,7];
$result = null;
for ($i = count($a)-1; $i >0; $i--){
if($result == null)
$result = $a[$i-1];
echo $result = $a[$i] - $result;
echo "<br />";
if($result == 0) break;
}
My first answer was wrong, i see you need to discard 2 keys after the first substraction.
This does the job:
<?php
$array = [3,4,5,5,6,7];
$reverse = array_reverse($array);
if (count($reverse) > 1) {
$first = $reverse[0] - $reverse[1];
} else {
//code should stop
}
$result = $first;
for ($i = 2; $i < count($reverse); $i++) {
$result = $reverse[$i] - $result;
}
echo $result;
Ouputs 0, just as in your example. And of course this code still needs check to see if the key of the array does exist while iterating
$numbers = [4,3,5,5,7,6];
sort($numbers);
$numbers = array_reverse($numbers);
$first = array_shift($numbers);
$second = array_shift($numbers);
$result = array_reduce($numbers, function ($carry, $current_item) {
return $current_item - $carry;
}, ($first - $second));
echo $result;
To get the expected output you are seeking you can use rsort to sort descending and start with the highest number. The first 2 elements are subtracted to get the starting value. Loop through the remainder to get your result.
Here's how you can achieve that:
$a = [4, 3, 5, 5, 7, 6]; // Your unsorted array
rsort($a); // Sort array by descending of largest to smallest
$result = $a[0] - $a[1]; // Initial subtraction of first two values
unset($a[0], $a[1]); // Remove from array so it won't loop through
foreach ($a as $_a) { // Loop through remainder and subtract difference
$result = $_a - $result;
}
echo $result; // Show your result
Yields:
0
If you care about reindexing due to the unset you can simply add an extra line after that:
$a = array_values($a); // Reindexes array starting at 0 if you desire
Given an array, I would like to display the count of distinct pairs of elements whose sum is equal to K -
I've written code as below, but I am unable to put array_diff to good use :\
<?PHP
function numberOfPairs($a, $k) {
$cnt = 0;
for($i=0; $i<count($a); $i++){
for($j=$i; $j<count($a); $j++){
if($a[$i]+$a[$j] == $k){
$arrRes[$i][0] = $a[$i];
$arrRes[$i][1] = $a[$j];
$cnt++;
}
}
}
sort($arrRes);
//print $cnt;
$d = $cnt;
for($i=0; $i<count($arrRes); $i++){
for($j=0; $j<count($arrRes); $j++){
$diff = array_diff($arrRes[$i], $arrRes[$j]);
if($diff == null)
$d += 1;
}
}
print $d;
}
$a = [6,6,3,9,3,5,1];
$k = 12;
numberOfPairs($a, $k);
?>
Here, the output arrays with sum equal to 12 are, i.e, the result of $arrRes is -
[0] => Array ( [0] => 3 [1] => 9 )
[1] => Array ( [0] => 6 [1] => 6 )
[2] => Array ( [0] => 6 [1] => 6 )
[3] => Array ( [0] => 9 [1] => 3 )
The count is 4, but the count should be 2, as (6,6) and (3,9) are the only distinct pairs.
You can simplify your solution, by using fact that arrays in php are hashmaps:
function numberOfPairs($a, $k) {
$used=[];
for ($i=0; $i<count($a); $i++)
for ($j=$i+1; $j<count($a); $j++) {
$v1 = min($a[$i], $a[$j]);
$v2 = max($a[$i], $a[$j]);
if ($k == $v1+$v2)
$used[$v1.'_'.$v2] = true;
}
return count($used);
}
$a = [6,6,3,9,3,5,1];
$k = 12;
echo numberOfPairs($a, $k);
You can create a flat array with used numbers and check so that you don't use them again with in_array.
function numberOfPairs($a, $k) {
$cnt = 0;
$used=[];
for($i=0; $i<count($a); $i++){
for($j=$i; $j<count($a); $j++){
if($a[$i]+$a[$j] == $k && !in_array($a[$i], $used) && !in_array($a[$i],$used)){
$arrRes[$i][0] = $a[$i];
$arrRes[$i][1] = $a[$j];
$used[] = $a[$i];
$used[] = $a[$j];
$used = array_unique($used);
$cnt++;
}
}
}
sort($arrRes);
//print $cnt;
// Not sure what the code below does, but I just left it the way it was.
$d = $cnt;
for($i=0; $i<count($arrRes); $i++){
for($j=0; $j<count($arrRes); $j++){
$diff = array_diff($arrRes[$i], $arrRes[$j]);
if($diff == null)
$d += 1;
}
}
print $d;
}
$a = [6,6,3,9,3,5,1];
$k = 12;
numberOfPairs($a, $k);
Try it here https://3v4l.org/lDe5V
Sort array and move indexes from both ends until they are not overlapped that gets O(n log n) instead of O(n^2) in accepted answer
function numberOfPairs($a, $k) {
sort($a);
$i = 0;
$j = count($a)-1;
// save last inseted array to avoid duplicates
$last = [];
while($i < $j) {
$s = $a[$i] + $a[$j];
if($s == $k) {
$t = [$a[$i++], $a[$j--]];
// Check for duplicate
if ($t != $last) {
$d[] = [$a[$i++], $a[$j--]];
$last = $t;
}
}
elseif($s > $k) $j--;
else $i++;
}
return $d;
}
demo
This is my method for finding distinct pairs of addends given an array and a target sum.
array_count_values() will reduce the input array size by condensing duplicate addends and storing them as keys (and their number of occurrences as values).
ksort() is called to ensure that the addends are processed in ascending order. This is crucial to avoid processing addends that are beyond the midpoint of the number set.
each iteration, store addends that are "less than or equal to" half of k AND have a matching addend.
when the addend multiplied by 2 is "greater than or equal to" k, do not continue to iterate.
Code: (Demo)
function numberOfPairs($a,$k){
$a=array_count_values($a); // enable use of the very fast isset() function and avoid iterating duplicates
ksort($a); // order so that only the lower values need to be iterated
foreach($a as $num=>$occur){
if(($double=$num*2)>=$k){ // we are at or past the middle
if($double==$k && $occur>1) $result[]=[$num,$k-$num]; // addends are equal and 2 exist, store before break
break;
}elseif(isset($a[$k-$num])){ // matching addend found, store & continue
$result[]=[$num,$k-$num];
}
}
var_export($result);
}
$a = [6,6,3,9,3,5,1];
$k = 12;
numberOfPairs($a,$k);
Output:
array (
0 =>
array (
0 => 3,
1 => 9,
),
1 =>
array (
0 => 6,
1 => 6,
),
)
array_count_values() is probably the most expensive function call in the snippet, but it sets up all subsequent processes to be fast, concise, direct, and logical (and I think, readable).
I'm using the following code to retrieve the highest 3 numbers from an array.
$a = array(1,2,5,10,15,20,10,15);
arsort($a, SORT_NUMERIC);
$highest = array_slice($a, 0, 3);
This code correctly gives me the highest three numbers array(20,15,10); however, I'm interested in getting the highest 3 numbers including the ones that are identical. In this example, I'm expecting to get an array like array(10, 10, 15, 15, 20)
Might be simpler but my brain is tired. Use arsort() to get the highest first, count the values to get unique keys with their count and slice the first 3 (make sure to pass true to preserve keys):
arsort($a, SORT_NUMERIC);
$counts = array_slice(array_count_values($a), 0, 3, true);
Then loop those 3 and fill an array with the number value the number of times it was counted and merge with the previous result:
$highest = array();
foreach($counts as $value => $count) {
$highest = array_merge($highest, array_fill(0, $count, $value));
}
You can use a function like this:
$a = array(1,2,5,10,15,20,10,15); //-- Original Array
function get3highest($a){
$h = array(); //-- highest
if(count($a) >= 3){ //-- Checking length
$c = 0; //-- Counter
while ($c < 3 || in_array($a[count($a)-1],$h) ){ //-- 3 elements or repeated value
$max = array_pop($a);
if(!in_array($max,$h)){
++$c;
}
$h[] = $max;
}
sort($h); //-- sorting
}
return $h; //-- values
}
print_r(get3Highest($a));
Of course you can improve this function to accept a dinamic value of "highest" values.
The below function may be usefull
$a = array(1,2,5,10,15,20,10,15);
function getMaxValue($array,$n){
$max_array = array(); // array to store all the max values
for($i=0;$i<$n;$i++){ // loop to get number of highest values
$keys = array_keys($array,max($array)); // get keys
if(is_array($keys)){ // if keys is array
foreach($keys as $v){ // loop array
$max_array[]=$array[$v]; // set values to max_array
unset($array[$v]); // unset the keys to get next max value
}
}else{ // if not array
$max_array[]=$array[$keys]; // set values to max_array
unset($array[$keys]); // unset the keys to get next max value
}
}
return $max_array;
}
$g = getMaxValue($a,3);
Out Put:
Array
(
[0] => 20
[1] => 15
[2] => 15
[3] => 10
[4] => 10
)
You can modify it to add conditions.
I thought of a couple of other possibilities.
First one:
Find the lowest of the top three values
$min = array_slice(array_unique($a, SORT_NUMERIC), -3)[0];
Filter out any lower values
$top3 = array_filter($a, function($x) use ($min) { return $x >= $min; });
Sort the result
sort($top3);
Advantages: less code
Disadvantages: less inefficient (sorts, iterates the entire array, sorts the result)
Second one:
Sort the array in reverse order
rsort($a);
Iterate the array, appending items to your result array until you've appended three distinct items.
$n = 0;
$prev = null;
$top = [];
foreach ($a as $x) {
if ($x != $prev) $n++;
if ($n > 3) break;
$top[] = $x;
$prev = $x;
}
Advantages: more efficient (sorts only once, iterates only as much as necessary)
Disadvantages: more code
This gives the results in descending order. You can optionally use array_unshift($top, $x) instead of $top[] = $x; to get it in ascending order, but I think I've read that array_unshift is less efficient because it reindexes the array after each addition, so if optimization is important it would probably be better to just use $top[] = $x; and then iterate the result in reverse order.
I have an array. I'd like to get the three highest values of the array, but also remember which part of the array it was in.
For example, if my array is [12,3,7,19,24], my result should be values 24,19,12, at locations 4, 0, 3.
How do I do that? The first part is easy. Getting the locations is difficult.
Secondly, I'd like to also use the top three OR top number after three, if some are tied. So, for example, if I have [18,18,17,17,4], I'd like to display 18, 18, 17, and 17, at location 0,1,2,3.
Does that make sense? Is there an easy way to do that?
Wouldn't you be there using asort()?
For example:
<?php
$list = [4,18,18,17,17];
// Sort maintaining indexes.
asort($list);
// Slice the first 3 elements from the array.
$top3 = array_slice($list, -3, null, true);
// Results in: [ 1 => 18, 2 => 18, 3 => 17 ]
Or you can use arsort
function getMyTop($list, $offset, $top) {
arsort($list);
return array_slice($list, $offset, $top, true);
}
$myTop = getMyTop($list, 0, 3);
$myNextTop = getMyTop($list, 3, 4);
This is what you need!
<?php
$array = array(12,3,7,19,24);
$array_processed = array();
$highest_index = 0;
while($highest_index < 3)
{
$max = max($array);
$index = array_search($max,$array);
$array_processed[$index] = $max;
unset($array[$index]);
$highest_index++;
}
print_r($array_processed);
?>
You will get Index as well as the value! You just have to define how many top values you want! Let me know if it's what you want!
function top_three_positions($array){
// Sort the array from max to min
arsort($array);
// Unset everything in sorted array after the first three elements
$count = 0;
foreach($array as $key => $ar){
if($count > 2){
unset($array[$key]);
}
$count++;
}
// Return array with top 3 values with their indexes preserved.
return $array;
}
You can use a loop to determine how many elements your top-three-with-ties will have, after applying arsort:
function getTop($arr, $num = 3) {
arsort($arr);
foreach(array_values($arr) as $i => $v) {
if ($i >= $num && $v !== $prev) return array_slice($arr, 0, $i, true);
$prev = $v;
}
return $arr;
}
// Sample input
$arr = [4,18,17,6,17,18,9];
$top = getTop($arr, 3);
print_r($top); // [5 => 18, 1 => 18, 4 => 17, 2 => 17]
try this:
public function getTopSortedThree(array $data, $n = 3, $asc = true)
{
if ($asc) {
uasort($data, function ($a, $b) { return $a>$b;});
} else {
uasort($data, function ($a, $b) { return $a<$b;});
}
$count = 0;
$result = [];
foreach ($data as $key => $value) {
$result[] = $data[$key];
$count++;
if ($count >= $n){
break;
}
}
return $result;
}
Send false for desc order and nothing for asc order
Send $n with number of top values you want.
This functionality doesn't losing keys.
This task merely calls for a descending sort, retention of the top three values, and in the case of values after the third-positioned value being equal to the third value, retain these as well.
After calling rsort(), call a for() loop starting from the fourth element ([3]). If the current value is not equal to the value in the third position, stop iterating, and isolate the elements from the front of the array to the previous iteration's index. Done.
p.s. If the input array has 3 or fewer elements, the for() loop is never entered and the whole (short) array avoids truncation after being sorted.
Code: (Demo)
$array = [18, 17, 4, 18, 17, 16, 17];
rsort($array);
for ($i = 3, $count = count($array); $i < $count; ++$i) {
if ($array[2] != $array[$i]) {
$array = array_slice($array, 0, $i);
break;
}
}
var_export($array);
Because the loop purely finds the appropriate finishing point of the array ($i), this could also be compacted to: (Demo)
rsort($array);
for ($i = 3, $count = count($array); $i < $count && $array[2] === $array[$i]; ++$i);
var_export(array_slice($array, 0, $i));
Or slightly reduced further to: (Demo)
rsort($array);
for ($i = 3; isset($array[2], $array[$i]) && $array[2] === $array[$i]; ++$i);
var_export(array_slice($array, 0, $i));
Output:
array (
0 => 18,
1 => 18,
2 => 17,
3 => 17,
4 => 17,
)
So I have an array like this:
$arr = [0, 1, 2];
Now I get a user input, e.g.
$input = 1;
Depending on that input I want to loop through all array elements starting from the position of that input.
Example:
//Array: [0, 1, 2]
Input: 0 Output: 012
Input: 1 Output: 120
Input: 2 Output: 201
I don't know much about PHP so I tried a simple for loop:
for($x = 1; $x <= 2; $x++)
{
echo $x;
}
But obviously this doesn't work, so I'm stuck from where I have to go from here.
So what you want to do is create an ArrayIterator.
Then set the position of the iterator with ArrayIterator::seek() depending on which input you get. You can get the position easily with array_search():
$it->seek(array_search($input, $arr));
(If the input isn't found in the array array_search() simply returns FALSE, which then gets used as 0, means you just loop through the array)
Then you can simply loop through the amount of elements you have in the array with a for loop starting from the set position. And if you hit the end of the array you just rewind it:
//End of array?
if(!$it->valid()){
//Start again
$it->rewind();
}
Code
<?php
$arr = [0, 1, 2];
$input = 1;
$it = new ArrayIterator($arr);
$it->seek(array_search($input, $arr));
for($i = 0, $length = count($arr); $i < $length; $i++){
if(!$it->valid()){
$it->rewind();
}
echo $it->current();
$it->next();
}
?>
output:
120
foreach( [1,2,0] as $num ){
echo $num;
}