Use array_count_values() and still keep key -- PHP - php

Let's say I have two arrays...
$radicand_array = array(3, 5, 5, 2);
$coeff_array = array(-10, 14, 3, -6);
I'd like to be able to determine which (if any) values in $radicand_array match, AND also know what the keys are. So, in this case I would want to know that there's a match on keys 1 and 2 of $radicand_array.
I need to know this because I want to then add the corresponding key values in $coeff_array. So, in this case I would then add 14 and 3 based on the matching 5's in $radicand_array.
I've tried array_count_values(), but it doesn't seem to give the key values like I want. Is there a PHP function ready made for this?

Using the link:
Fixed. Good man!
<?php
// $radicand_array = array(3, 5, 5, 2);
$radicand_array = array(3, 5, 5, 2, 3, 3);
$coeff_array = array(-10, 14, 3, -6);
$unique = array_unique($radicand_array);
$duplicates = array_diff_assoc($radicand_array, $unique);
// Duplicate keys
$aDupes = array_keys(array_intersect($radicand_array, $duplicates));
$iSum = 0;
$iCountDupes = count( $aDupes );
for( $i = 0; $i < $iCountDupes; ++$i )
{
if( !empty( $coeff_array[ $aDupes[ $i ] ] ) )
{
$iSum = $iSum + $coeff_array[ $aDupes[ $i ] ];
}
}
var_dump( $iSum );
?>

This is an edited version of Vladimir Ramik's post to handle multiple sets of matches...
$radicand_array = array(3, 5, 5, 2, 3);
$coeff_array = array(-10, 14, 3, -6, 4);
$unique = array_unique($radicand_array);
$duplicates = array_diff_assoc($radicand_array, $unique);
$new_array = array_chunk($duplicates, 1);
// Duplicate keys
$aDupes = array_keys(array_intersect($radicand_array, $new_array[0]));
$iCountDupes = count( $aDupes );
for($i = 0; $i < $iCountDupes; ++$i){
$ans_coeff_1 += $coeff_array[$aDupes[ $i ]];
}
echo $ans_coeff_1;
// Duplicate keys
$bDupes = array_keys(array_intersect($radicand_array, $new_array[1]));
$iCountDupes = count( $bDupes );
for($i = 0; $i < $iCountDupes; ++$i){
$ans_coeff_2 += $coeff_array[$bDupes[ $i ]];
}
echo '<br>' . $ans_coeff_2;

Related

Find all possible combinations with two differents arrays

$array1 = [null, 6, null];
$array2 = [1,2,3,4];
How do I find all possible unique combinations of these two lists (Should be the same lenght of array1 and keep the 6 in the same position);
Need to return
[1, 6, 2],[1, 6, 3],[1, 6, 4],[2, 6, 3],[2, 6, 4],[3, 6, 4]
You can use the below logic
$array1 = [null, 6, null];
$array2 = [1,2,3,4];
$final = [];
for($i = 0;$i < count($array2);$i++){
for($j = $i + 1;$j < count($array2);$j++){
for($k = 0;$k < count($array1);$k++){
if(!is_null($array1[$k])){
$final[] = [$array2[$i], $array1[$k], $array2[$j]];
}
}
}
}
print_r($final);

Need Three Highest Values (or more, if tied) of PHP Array and Their Location?

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,
)

How to get common minimum value in two arrays

I have a function where is checks on two arrays and returns the common minimum value in both the arrays. IT returns the correct answer when both the arrays have equal number of elements. But is the other other is bigger it does not return the correct one. How to overcome this?
<?php
$A = array(0);
$B= array(1,0);
$n = sizeof($A);
$m = sizeof($B);
sort($A);
sort($B);
$i = 0;
for ($k = 0; $k < $n; $k++) {
if ($i < $m - 1 AND $B[$i] < $A[$k])
$i += 1;
if ($A[$k] == $B[$i])
echo $A[$k];
}
echo "end";
?>
Thanks
A way simpler way would be to take the minimum value of the intersection of your arrays :
$array = array (5,6,7,8,9);
$array2 = array (9,7,5,3,4,1);
$min = min(array_intersect($array, $array2));
echo $min; // 5
Leverage PHP function array_intersect() to extract common values in two arrays, then fetch the minumum value by using min()
Like so:
<?php
$arrayOne = [1, 3, 5, 6, 7];
$arrayTwo = [0, 9, 2, 3, 4, 5];
echo min(array_intersect($arrayOne, $arrayTwo)); // 3
I would use array_intersect. It will give you an array with only values that are present in both arrays you are looking through, then you can find the lowest value in the array
$A = array(0,5,4,3,2,1,4);
$B = array(0,1,3,4);
$C = array_intersect($A, $B);
$low = $C[0];
for($i = 0; $i < count($C); $i++) {
if($C[$i] < $low)
$low = $C[$i];
}
echo "Lowest shared number is $low";

Merge two flat indexed arrays of equal size so that values are pushed into the result in an alternating fashion

Suppose I have two arrays:
$a1 = array(0, 1, 2);
$a2 = array(3, 4, 5);
I want to be able to do a merge technique that alternates the array values and not just concatenate them. I want this result:
array(0, 3, 1, 4, 2, 5);
Is there a native way to do this as performance is an issue here since I need to do this thousands of times
Please note, I know I can do it like this:
for (var $i = 0; $i < count($a1); $i++) {
newArray[] = $a1[$i];
newArray[] = $b1[$i];
}
I'm looking for a built in way if there is a faster one.
$count = count($a1);
for ($i = 0; $i < $count; $i++) {
$newArray[] = $a1[$i];
$newArray[] = $b1[$i];
}
My work here is done.
$a1 = array(0,1,2);
$a2 = array(3,4,5);
$start = microtime(TRUE);
for($t = 0; $t < 100000; $t++)
{
$newArray = array();
$count = count($a1);
for ($i = 0; $i < $count; $i++)
{
$newArray[] = $a1[$i];
$newArray[] = $a2[$i];
}
}
echo round(microtime(TRUE) - $start, 2); # 0.6
$a1 = array(0,1,2);
$a2 = array(3,4,5);
$start = microtime(TRUE);
for($t = 0; $t < 100000; $t++)
{
$newArray = array();
for ($i = 0; $i < count($a1); $i++)
{
$newArray[] = $a1[$i];
$newArray[] = $a2[$i];
}
}
echo round(microtime(TRUE) - $start, 2); # 0.85
So pre-counting array size will be ~1/4 [citation needed] (on freakin' 100.000 iterations you will gain 0.2 in total) faster. If you put count() inside loop, it will recount on every iteration. 1/4 seems to me a reasonably faster. If you are looking for compiled function, you can stop.
P.S. Benchmark is like bikini, it shows you everything, and nothing.
Since you are "zippering" two indexed arrays, you can "transpose and flatten". I expect that this will not be quite as fast as using a for() or foreach(), but on small input arrays, there will be no noticeable drag on performance. In other words, when coding style or minimal declared variables is sought, then the following technique should be considered.
Code: (Demo)
$a1 = [0, 1, 2];
$a2 = [3, 4, 5];
var_export(
array_merge(...array_map(null, $a1, $a2))
);
Output:
array (
0 => 0,
1 => 3,
2 => 1,
3 => 4,
4 => 2,
5 => 5,
)
As a funky little function-less approach, you can push the $a1 value from the foreach() value declaration and inside the loop's body, you can push the $a2 value. Feast your eyes... (Demo)
$result = [];
foreach ($a1 as $index => $result[]) {
$result[] = $a2[$index];
}
var_export($result);
// same output as earlier snippet
For anyone that is hunting for an associative-safe technique, you could make looped slice or splice calls. Be aware that splice() will mutate/consume the input arrays in the process. (Slice Demo) (Splice Demo)
$result = [];
for ($i = 0, $count = count($a1); $i < $count; ++$i) {
$result += array_slice($a1, $i, 1)
+ array_slice($a2, $i, 1);
}
or
$result = [];
while($a1 && $a2) {
$result += array_splice($a1, 0, 1)
+ array_splice($a2, 0, 1);
}
p.s. I even build this utility snippet to offer more dynamic tooling of how many elements should be inserted and how frequently from each array while merging. See Insert elements from one array (one-at-a-time) after every second element of another array (un-even zippering).

Counting Sort in PHP

In a PHP project I have some data I want to sort using a linear time, simple counting sort:
$ar = array(7, 2, 0, 3, 8, 0, 12, 7, 6, 7);
$count = array();
foreach ($ar as $v)
$count[$v]++;
$sorted = array();
foreach ($count as $v => $c)
for ($i = 0; $i < $c; $i++)
$sorted[] = $v;
The problem is that the above obviously doesn't work. The php array works more like a hashmap than an array. The code can be made to work by inserting ksort($count) before the final loop, but ksort runs in O(nlogn) which destroys the entire point.
Is there any way to do a linear time sort in php? Perhaps using some paramter to array(), or some entirely different structure?
You didn't follow the algorithm correctly. This is O(n).
$ar = array(7, 2, 0, 3, 8, 0, 12, 7, 6, 7);
$count = array();
foreach ($ar as $v) {
$count[$v] = isset($count[$v]) ? $count[$v] + 1 : 1;
}
$sorted = array();
$min = min($ar);
$max = max($ar);
for ($i=$min; $i<=$max; $i++) {
if (isset($count[$i])) {
for ($j=0; $j<$count[$i]; $j++) {
$sorted[] = $i;
}
}
}
also, see array_count_values(), or alternatively compute the min and max inside the counting loop.
Approved answer is wrong. Correct:
$ar = array(7, 2, 0, 3, 8, 0, 12, 7, 6, 7);
$count = array();
foreach ($ar as $v) {
$count[$v] = isset($count[$v]) ? $count[$v] + 1 : 1;
}
$sorted = array();
$min = min($ar);
$max = max($ar);
for ($i=$min; $i <= $max; $i++) {
if (isset($count[$i])) {
for ($j=0; $j<$count[$i]; $j++) {
$sorted[] = $i;
}
}
}
If i understand your question AND comment correctly, just using sort($count) would work no?
$ar = array(7, 2, 0, 3, 8, 0, 12, 7, 6, 7);
$sorted = $ar;
sort($sorted);
var_dump($ar);
var_dump($sorted);
Result:
array(7,2,0,3,8,0,12,7,6,7);
array(0,0,2,3,6,7,7,7,8,12);
But i'm wondering what the foreach($ar as $v)$count[$v]++; does... doesn't really make sense...
Adding some comments to the code to show you why this doesn't do what you think it should do.
$ar = array(7, 2, 0, 3, 8, 0, 12, 7, 6, 7);
$count = array();
foreach ($ar as $v) {
// add each number in $ar to $count.
// the first number in $ar is 7, so 7 will be the first number in $count.
// because 7 is in $ar 3 times, $count[7] == 3.
$count[$v]++;
}
// the output of print_r will be very revealing:
print_r($count);
/*Array
(
[7] => 3
[2] => 1
[0] => 2
[3] => 1
[8] => 1
[12] => 1
[6] => 1
)*/
$sorted = array();
foreach ($count as $v => $c) {
// the first entry: $count[7] == 3
// so add 7 to $sorted 3 times.
// the second entry: $count[2] == 1
// so add 2 to $sorted 1 time.
// etc.
for ($i = 0; $i < $c; $i++) {
$sorted[] = $v;
}
}
This simply groups numbers together based on their location in the first array.
To get the sorted $ar in a variable of it's own ($sorted), it's pretty trivial:
$sorted = $ar;
sort($sorted);
Which makes me think that your question and comment is not giving the whole picture.
Edit: Now after you have clarified that you wanted to implement a specific algorithm (and you actually got an answer already that shows some points that were wrong implementing it first), I think it's worth to focus on another aspect of your question:
You're comparing the complexity of two (theoretical) algorithms, but you're leaving aside how the algorithms are implemented.
PHP's sort() - even based on "bad" quicksort, will outrun your own PHP usercode implementation of some other algorithm by numbers.
You just have compared the wrong parameters here. The complexity of a function does not says much when you compare a build-in PHP function with some function in your user-code.
$A = [1, 2, 2, 2, 1, 3, 3, 1, 2, 4, 5, 0, 0]; // example array
$m = max($A);
$count = array_fill(0, $m + 1, '0');
foreach ($A as $value) $count[$value] += 1;
// next step is print the numbers
$a = [];
foreach ($count as $key => $value) {
for ($i = 0; $i < $value;) {
array_push($a, $key);;
$i++;
}
}
var_dump($count); // print the sorted array
var_dump($a); // print the numbers (low to high)

Categories