Array divide/split by value - php

$a = array(8, 16, 16, 32, 8, 8, 4, 4);
With an array like the one above is there a way so I can divide/split the array based on the value suming up to a set value. e.g if I wanted them to equal 32. My final array will have upto 100 values all being either 32, 16, 8 or 4 and I just need to group the items so the value always equal a set amount so in this example its 32.
From the above array I would would hope to get:
$a[0][1] = 16
$a[0][2] = 16
$a[1][3] = 32
$a[2][0] = 8
$a[2][4] = 8
$a[2][5] = 8
$a[2][6] = 4
$a[2][7] = 4
as $a[0] sums up to 32 and so does $a[1] and $a[2].

$a = array(8, 16, 16, 32, 8, 8, 4, 4);
$limit = 32;
rsort($a);
$b = array(array());
$index = 0;
foreach($a as $i){
if($i+array_sum($b[$index]) > $limit){
$b[++$index] = array();
}
$b[$index][] = $i;
}
$a = $b;
print_r($a);
It will work, but only because in your case you have 4 | 8 | 16 | 32, and only if the needed sum is a multiple of the biggest number (32).
Test: http://codepad.org/5j5nl3dT
Note: | means divides.

$a = array(8, 16, 16, 32, 8, 8, 4, 4);
$group_limit = 32;
$current_group = $result = array();
$cycles_since_successful_operation = 0;
while ($a && $cycles_since_successful_operation < count($a))
{
array_push($current_group,array_shift($a));
if (array_sum($current_group) > $group_limit)
array_push($a,array_pop($current_group));
elseif (array_sum($current_group) < $group_limit)
$cycles_since_successful_operation = 0;
elseif (array_sum($current_group) == $group_limit)
{
$result []= $current_group;
$current_group = array();
$cycles_since_successful_operation = 0;
}
}
if ($a)
$result []= $a; // Remaining elements form the last group
http://codepad.org/59wmsi4g

function split_into_thirtytwos($input_array) {
$output_array=array();
$work_array=array();
$sum=0;
sort($input_array,SORT_NUMERIC);
while(count($input_array)>0) {
$sum=array_sum($work_array)+$input_array[count($input_array)-1];
if($sum<=32) {
$work_array[]=array_pop($input_array);
} else {
$output_array[]=$work_array;
$work_array=array();
}
}
if(count($work_array)>0) {$output_array[]=$work_array;}
return $output_array;
}
Tested with your input:
Array
(
[0] => Array
(
[0] => 32
)
[1] => Array
(
[0] => 16
[1] => 16
)
[2] => Array
(
[0] => 8
[1] => 8
[2] => 8
[3] => 4
[4] => 4
)
)

Related

array matching count one less than expected

$ar is a sock of pairs. $n is the number of items in $ar. I have to match each number in the array with another if any of them match, its a pair. I have to then return the count of matched items. I have done it below but the answer is one less than what it should be. Example
n:9
ar: 10 20 20 10 10 30 50 10 20
I get output 2 instead of 3.
function sockMerchant($n, $ar) {
$pair =0;
$j=0;
for($i=0; $i< count($ar); $i++)
{
for($j=$i+1; $j< count($ar); $j++)
{
if ( isset( $ar[$j]) && isset( $ar[$i])) {
if ($ar[$i]== $ar[$j])
{
unset($ar[$i]);
unset($ar[$j]);
$pair+=1;
$i=0;
break;
}
}
}
}
return count($ar);
}
Instead of what you are doing there is shortcut to achieve the same,
$temp = array_count_values($arr); // count number of occurences
echo count(array_filter($temp, function($value){ // filter in not greater than 1
return $value > 1;
}));
The above snippet will give you all the pairs which are not only once.
Here is an one more alternative for your snippet,
$temp = array_count_values($arr); // count number of occurences
$e = array_reduce($temp, function ($carry, $item) {
$carry += ($item > 1 ? intval($item / 2) : 0);
return $carry;
});
echo $e;die;
Working demo.
$ar = [10, 20, 20, 10, 10, 30, 50, 10, 20];
$pairIndex = [];
$count = 0;
foreach ($ar as $key => $item) {
// Start comparing from the next element
for ($i = ($key + 1); $i < count($ar); $i++) {
if ($item == $ar[$i] && !in_array($key, $pairIndex)) {
$pairIndex[] = $key;
$pairIndex[] = $i;
$count++;
}
}
}
echo "Pairs: " . $count;
This will give you the number of pairs.
$arr = array(10, 20, 20, 10, 10, 30, 50, 10, 20);
$counts = array_count_values($arr); // count number of occurences
array_walk($counts, function(&$x) {$x = intdiv($x, 2);}); //divide each element
//by 2 (integer division), so now you have pairs of each element
echo array_sum($counts); //sum the pairs
Using your initial array, it echoes 3.
simple example what happens to your array:
$ar = array(0, 10, 20, 30, 40, 50 , 60, 70, 80, 90);
$lnPointer = 2;
print_r($ar);
// Array ( [0] => 0 [1] => 10 [2] => 20 [3] => 30 [4] => 40 [5] => 50 [6] => 60 [7] => 70 [8] => 80 [9] => 90 )
echo "<HR>";
echo $ar[$lnPointer];
echo "<HR>";
unset( $ar[$lnPointer]);
print_r($ar);
// Array ( [0] => 0 [1] => 10 [3] => 30 [4] => 40 [5] => 50 [6] => 60 [7] => 70 [8] => 80 [9] => 90 )
echo "<HR>";
echo $ar[$lnPointer];
after unsetting you get an undefined index
If you want total matched pair count then you should return $pair. But you are returning count($ar) which can not be correct in all the possible scenarios. Check the below code with output and new set of data:
<?php
function sockMerchant($n, $ar) {
$pair =0;
$j=0;
for($i=0; $i< $n; $i++)
{
for($j=$i+1; $j< $n; $j++)
{
if ( isset( $ar[$j]) && isset( $ar[$i])) {
if ($ar[$i]== $ar[$j])
{
unset($ar[$j]);
unset($ar[$i]);
$pair+=1;
$i=0;
break;
}
}
}
}
echo '<pre>'; print_r($ar);
return $pair.'--'.count($ar);
}
$a = [10, 20, 20, 10, 10, 30, 50, 10, 20, 80, 40];
$n = 11;
$b = sockMerchant($n, $a);
var_dump($b);
// Output:
/*
Array
(
[5] => 30
[6] => 50
[8] => 20
[9] => 80
[10] => 40
)
string(4) "3--5"
*/
?>
Demo

Make new array values from element value plus the previous element's value

I have array like this :
$array = array(1, 4, 8, 3, 7);
I want sum the value of array but first, I unshift the array like this :
<?php
$array = array(1, 4, 8, 3, 7);
array_unshift($array, 0);
array_pop($array);
foreach($array as $key => $val) {
echo $val;
}
?>
then I want sum array first (1, 4, 8, 3, 7) with new array (0, 1, 4, 8, 3)
sum like 1 plus 0 and 4 plus 1 and 8 plus 4 etc
And I want the output is : 1, 5, 12, 11, 10
Just use array_map.
array_map allows you to use a custom function on multiple arrays at the same time
$array = array(1, 4, 8, 3, 7);
$others = $array;
array_unshift($others, 0);
array_pop($others);
function sumarray($v1,$v2){
return $v1+$v2;
}
$res = array_map('sumarray', $array,$others);
print_r($res);
result like
Array
(
[0] => 1
[1] => 5
[2] => 12
[3] => 11
[4] => 10
)
You can use for loop instead of foreach.
Example
$array = $array2 = array(1, 4, 8, 3, 7);
array_unshift($array, 0);
array_pop($array);
$array3 = [];
for($i = 0; $i < count($array); $i++) {
$array3[] = $array[$i]+$array2[$i];
}
print_r($array3);
Output
Array
(
[0] => 1
[1] => 5
[2] => 12
[3] => 11
[4] => 10
)
You can store the popped value in a variable (popped) so you can use it later. Then you can use a regular for loop to loop over your array and add the popped value to the array once the loop is complete:
$array = array(1, 4, 8, 3, 7);
array_unshift($array, 0);
$popped = array_pop($array);
$result = [];
for($i = 0; $i < count($array)-1; $i++) {
$val1 = $array[$i];
$val2 = $array[$i + 1];
$result[] = $val1 + $val2;
}
$result[] = end($array) + $popped; // add the last element with the popped value
print_r($result);
Output:
Array ( [0] => 1 [1] => 5 [2] => 12 [3] => 11 [4] => 10 )
There is no need to pop or shift any elements and there is no need to create a copy of the input array.
As you iterate the input array, sum the current value with the previous value. If there is no previous value, use zero. This is exceedingly simple since your input is an indexed array.
Code: (Demo)
$array = [1, 4, 8, 3, 7];
$result = [];
foreach ($array as $index => $value) {
$result[] = $value + ($array[$index - 1] ?? 0);
}
var_export($result);
// [1, 5, 12, 11, 10]

How can I determine two numbers that are more close than others in an array

I have this array:
$arr = array (20, 1, 5, 10, 7, 16);
I would like to get 5 and 7. Because these are more close to each other than other items. In other word the difference between them is the lowest number:
7 - 5 = 2 // 2 is lowest number as the difference between all array's items
How can I do that?
$keep = $arr[0];
$diff = $arr[1] - $arr[0];
foreach ($arr as $item) {
if ( ($keep - $item) < $diff && $keep != $item ) {
$diff = $item;
}
}
My code is incomplete, Because it just compares first item with other items.
Explanation
So to get the two numbers in an array which are the closest to each other you have to compare each value with each other value. But you don't have to compare them with themselves and to the previous ones which you already compared.
To calculate how many comparisons you have to do you can use the binomial coefficient:
(n) n!
(k) → ─────────────
k! * (n - k)!
Where n is the total amount of elements and k how many you pick
And in your example this would mean:
n = 6 //Array elements
k = 2 //Two values which you compare
6! 720
───────────── → ───────────── = 15 comparison
2! * (6 - 2)! 2 * 24
Visualized
20 , 1 , 5 , 10 , 7 , 16 //Array values
↓ ↑ ↑ ↑ ↑ ↑
└────┴───┴───┴────┴───┘ //20 compared to all values, except itself
↓ ↑ ↑ ↑ ↑
└───┴───┴────┴───┘ //1 compared to all values, except itself + [20]
↓ ↑ ↑ ↑
└───┴────┴───┘ //5 compared to all values, except itself + [20, 1]
↓ ↑ ↑
└────┴───┘ //10 compared to all values, except itself + [20, 1, 5]
↓ ↑
└───┘ //7 compared to all values, except itself + [20, 1, 5, 10]
//16 compared to all values, except itself + [20, 1, 5, 10, 7]
Now to do this in code we need 2 loops to loop over the entire array for each value of the first loop. But as we already said we can ignore the value itself and the previous values, so for this we use 2 for loops and set the key, for the inner loop, to be the outer key + 1.
for($key = 0, $length = count($arr); $key < $length; $key++){
for($innerKey = $key + 1; $innerKey < $length; $innerKey++){
//↑ Skipping the previous values and the value itself
}
}
In the inner loop itself we just need to access the current value of the outer loop and get the difference compared to the value of the inner loop. That this also works with negative numbers we just wrap it into an abs() call to make the difference always positive.
Then we just check if the difference is smaller than the smallest difference which we already found, saved in $nearest. (We initialized $nearest by the difference of the biggest and smallest value of the array + 1):
if( ($diff = abs($arr[$keys[$key]] - $arr[$keys[$innerKey]])) < $nearest)
If the difference is smaller than the smallest difference which we already found, we write the two values into an array and set the new smallest difference:
$result = [$arr[$keys[$key]], $arr[$keys[$innerKey]]];
$nearest = $diff;
Code
<?php
$arr = [20, 1, 5, 10, 7, 16];
$keys = array_keys($arr);
$nearest = max($arr) - min($arr) + 1;
$result = [];
for($key = 0, $length = count($arr); $key < $length; $key++){
for($innerKey = $key + 1; $innerKey < $length; $innerKey++){
if( ($diff = abs($arr[$keys[$key]] - $arr[$keys[$innerKey]])) < $nearest){
$result = [$arr[$keys[$key]], $arr[$keys[$innerKey]]];
$nearest = $diff;
}
}
}
print_r($result);
?>
Output
[5, 7]
PHP usort is used here, as a note it is implemented with quicksort.
$temp ==> Temporary array to store the two values and its differences while looping
$temp = [arr[$i] , arr[$j] , arr[$i]-arr[$j] ]
$arr = array (20, 1, 5, 10, 7, 16);
$temp=array();
for ($i = 0; $i < count($arr)-1; $i++)
{
$diff=0;
for ($j = $i+1; ($j < count($arr) && $i!=$j); $j++)
{
$diff=abs($arr[$i]-$arr[$j]); //finding difference &taking absolute
$temp[] = array($arr[$i],$arr[$j], $diff);
}
}
usort($temp,function ($a, $b) { return $b[2] < $a[2]; });//sort `$temp[]` in ascending order according to the difference value
list($x,$y,$d) = $temp[0]; //the first row of `$temp` contains values with the diff. is lowest
//and the values is stored to `$x` & `$y` and there difference in `$d`
echo "Related Values are $x and $y by $d";
Check results here http://ideone.com/pZ329m
Working
20 1 5 10 7 16 //inner loop -----------------------
| | | | | | $temp[]=[[20,1,19],[20,5,15],[20,10,10],...//$i=0 |// `20` is compared values from 1 onwards and the values and differences are stored in `$temp[]`
|___|____|___|___|___| //(eg., $temp=[20,1,|20-1|]) //$j=1,2,3,4,5↓
| | | | | [1,5,4],[1,10,9],... //$i=1 | `1` is compared with values from 5 onwards
|____|___|___|___| //$j=2,3,4,5 ↓outer loop
| | | | [5,10,5],[5,7,2],... //$i=2 | `5` is compared with values from 10 onwards
|___|___|___| //$j=3,4,5 ↓
| | | [10,7,3],[10,16,6] //$i=3 | `10` is compared with values from 7 onwards
|___|___| //$j=4,5 ↓
| | [7,16,9]] //$i=4 |`7` is compared with final value `16`
|___| //$j=5 ↓
After getting $temp[] , it's sorted in ascending order according to the differences .
Then the first row of $temp[] gives our desired result .
Whats inside $temp[]
Array
(
[0] => Array
(
[0] => 7
[1] => 5
[2] => 2
)
[1] => Array
(
[0] => 7
[1] => 10
[2] => 3
)
[2] => Array
(
[0] => 16
[1] => 20
[2] => 4
)
[3] => Array
(
[0] => 5
[1] => 1
[2] => 4
)
[4] => Array
(
[0] => 10
[1] => 5
[2] => 5
)
[5] => Array
(
[0] => 16
[1] => 10
[2] => 6
)
[6] => Array
(
[0] => 7
[1] => 1
[2] => 6
)
[7] => Array
(
[0] => 16
[1] => 7
[2] => 9
)
[8] => Array
(
[0] => 10
[1] => 1
[2] => 9
)
[9] => Array
(
[0] => 10
[1] => 20
[2] => 10
)
[10] => Array
(
[0] => 16
[1] => 5
[2] => 11
)
[11] => Array
(
[0] => 7
[1] => 20
[2] => 13
)
[12] => Array
(
[0] => 5
[1] => 20
[2] => 15
)
[13] => Array
(
[0] => 16
[1] => 1
[2] => 15
)
[14] => Array
(
[0] => 1
[1] => 20
[2] => 19
)
)
As i comment to use 2 loop and a condition, i did the same thing. Just check it out and let me know.
$arr = array (20, 1, 5, 10, 7, 16);
$c = count($arr);
$ld = max($arr);
for($i = 0; $i < $c; $i++){
for($j = $i+1; $j < $c; $j++){
$abs = abs($arr[$i]-$arr[$j]);
if($abs < $ld)
$ld = $abs;
}
}
echo $ld; //2
if you need to know which two value has the difference then it is possible, just store them inside the if condition.
Well, quick and dirty... two loops, one condition
//$arr = array (20, 1, 5, 10, 7, 16); gives 5 and 7
$arr = array (-32,-15,4,6,-14,613,4,63,6,4);
$diff = INF;
foreach ($arr as $item0) {
foreach ($arr as $item1) {
$localdiff = abs($item0 - $item1);
if ( $localdiff > 0 && $localdiff < $diff ) {
$diff = $localdiff;
$keep0 = $item0;
$keep1 = $item1;
}
}
}
echo "Smallest distance was $diff, between $keep0 and $keep1";
Check it out on http://ideone.com/WdWOcb
use this
$arr = array (20, 1, 5, 10, 7, 16);
$temp = array();
foreach ($arr as $item1) {
foreach ($arr as $item2) {
$aV = abs($item1-$item2);
if(!in_array($aV, $temp) && $aV!=0)
$temp[$item1."-".$item2] =$aV;
}
}
$closest = array_keys($temp,min($temp));
list($first,$explode,$second) = $closest[0];
print "The two closest numbers are " . $first . " and " . $second;
$arr = array(20, 1, 5, 10, 7, 16);
$min = max($arr);
$closest = array();
foreach ($arr as $i) {
foreach ($arr as $j) {
if ($i != $j) {
$diff = abs($i - $j);
if ($min > $diff) {
$min = $diff;
$closest[0] = $i;
$closest[1] = $j;
}
}
}
}
print "The two closest numbers are " . $closest[0] . " and " . $closest[1];
It's not clear what happens in this situation:
$arr = array( 14, 20, 1, 5, 10, 7, 16 );
In above case you have two couples with 2 as difference ( 7-5, 16-14 ). Following code returns all relative values.
We execute the standard two nested loops for comparing all elements (main loop excluding last element, nested loop starting from main index +1), then if the difference between current values is lower than previously retrieved difference, we replace it; otherwise, if the difference is equal to previous difference, we append a new couple:
$result = array( 'sum' => INF, 'values'=> array() );
for( $i=0; $i < count( $arr )-1; $i++ )
{
for( $j = $i+1; $j < count( $arr ); $j++ )
{
$dif = abs( $arr[$i] - $arr[$j] );
if( $dif < $result['sum'] )
{
$result = array( 'sum' => $dif, 'values'=> array( array( $arr[$i], $arr[$j] ) ) );
}
elseif( $dif == $result['sum'] )
{
$result['values'][] = array( $arr[$i], $arr[$j] );
}
}
}
At this point, for above array sample, you have this result:
Array
(
[sum] => 2
[values] => Array
(
[0] => Array
(
[0] => 14
[1] => 16
)
[1] => Array
(
[0] => 5
[1] => 7
)
)
)
If you are interested in all value, simply you can find them in $result['values']. Otherwise, if you want (i.e.) min values (5 and 7), you can usort-it:
usort( $result['values'], function( $a, $b ) { return min($a)-min($b); } );
and use $result['values'][0]:
[0] => Array
(
[0] => 5
[1] => 7
)
try this
$arr = array (20, 1, 5, 10, 7, 16);
arsort($arr, SORT_NUMERIC);
$arr = array_values( $arr );
$min = 0;
foreach( $arr as $index => $number ){
if( isset($arr[$index+1]) ){
$diff = abs( $number - $arr[$index+1] );
if( $diff < $min || $min == 0 ){
$min = $diff;
$result = array( $number, $arr[$index+1] );
}
}
}
print_r( $result );

Getting specidic values from PHP arrays

Is there a way to get the first value from array, then the first value key + 3 ; then +6 then + 9 ans so on
Take this array for example,
array(1,2,5,14,19,2,11,3,141,199,52,24,16)
i want extract a value every 3 so the result would be
array(1,14,11,199,16)
Can i do that with existing PHP array function?
Use a for loop and increment the counter variable by 3.
for ($i = 0; $i <= count(your array); $i+3) {
echo $myarray[i]
}
The following is function that will handle extracting the values from a given array. You can specify the number of steps between each value and if the results should use the same keys as the original. This should work with regular and associative arrays.
<?php
function extractValues($array, $stepBy, $preserveKeys = false)
{
$results = array();
$index = 0;
foreach ($array as $key => $value) {
if ($index++ % $stepBy === 0) {
$results[$key] = $value;
}
}
return $preserveKeys ? $results : array_values($results);
}
$array = array(1, 2, 5, 14, 19, 2, 11, 3, 141, 199, 52, 24, 16);
$assocArray = array('a' => 1, 'b' => 2, 'c' => 5, 'd' => 14, 'e' => 19, 'f' => 2, 11, 3, 141, 199, 52, 24, 16);
print_r(extractValues($array, 3));
print_r(extractValues($array, 3, true));
print_r(extractValues($assocArray, 5));
print_r(extractValues($assocArray, 5, true));
?>
Output
Array
(
[0] => 1
[1] => 14
[2] => 11
[3] => 199
[4] => 16
)
Array
(
[0] => 1
[3] => 14
[6] => 11
[9] => 199
[12] => 16
)
Array
(
[0] => 1
[1] => 2
[2] => 52
)
Array
(
[a] => 1
[f] => 2
[4] => 52
)
Use a loop and check the key.
$result = array();
foreach($array as $key => $value) {
if ($key % 3 === 0) {
$result[] = $value;
}
}
Try below one:
<?php
$your_array = array (1,2,5,14,19,2,11,3,141,199,52,24,16);
$every_3 = array();
$i = 0;
foreach($your_value as $value) {
$i++;
if($i%3==0){
$every_3[]=$value;
}
}
var_dump($every_3);
?>
Do like this
$arr=array (1,2,5,14,19,2,11,3,141,199,52,24,16);
$narr=array();
for($i=0;$i<count($arr);$i=$i+3){
$narr[]=$arr[$i]
}
print_r($narr);
<?php
$mynums = array(1,2,5,14,19,2,11,3,141,199,52,24,16);
foreach ($mynums as $key => $value) {
if ( $key % 3 === 0)
{
$newnum[] = $value;
}
}
var_dump($newnum);
?>
$data = array(1,2,5,14,19,2,11,3,141,199,52,24,16);
$matches = array();
foreach($data as $key => $value)
{
if($key%3 === 0)
{
$matches[] = $value;
}
}
var_dump($matches);
The only way you could do it would be to use a loop, count the length of an array, and loop through using a % mathmatical operator.
It gives you a remainder of a division: http://au2.php.net/operators.arithmetic

To compare two arrays while considering duplicate value

i have two arrays
$array1 = array(1, 2, 2, 3);
$array2 = array( 1, 2, 3,4);
and when did :
var_dump(array_diff($array1, $array2));
getting :
array(0){}
as output , but i am looking for :
array(1){[2]=>2}
can someone please let me know how to do it
Thanks in Advance
Try this
$array1 = array(1, 2, 2, 3, 4, 5, 5, 7);
$array2 = array(1, 2, 4, 6, 3, 3, 5);
$diff = array_filter($array1,
function ($val) use (&$array2) {
$key = array_search($val, $array2);
if ( $key === false ) return true;
unset($array2[$key]);
return false;
}
);
print_r($diff);
// Array ( [2] => 2 [6] => 5 [7] => 7 )
If you want to count number of duplicate element from same array as well as from multiple arrays, please use below code,
<?php
$array1 = array(1,2,2,3,7);
$array2 = array(1,2,3,4);
$diff_array = array();
$diff_array1 = array_count_values($array1);
$diff_array2 = array_count_values($array2);
$a = array_keys($diff_array1);
$b = array_keys($diff_array2);
for($i=0;$i<count($a);$i++)
{
if($a[$i] == $b[$i])
{
$x = $a[$i];
$y = $b[$i];
$diff_array1[$x] += $diff_array2[$y];
}
}
$diff_array1=array_diff($diff_array1, array('1'));
echo '<pre>';
print_r($diff_array1);
?>
This will get you the desired result:
$array1 = array(1, 2, 2, 3);
$array2 = array( 1, 2, 3,4);
$countArray1 = array_count_values($array1);
$countArray2 = array_count_values($array2);
foreach($countArray1 as $value=>$count) {
if($count > 1) $dupArray[] = $value;
}
foreach($countArray2 as $value=>$count) {
if($count > 1) $dupArray[] = $value;
}
print_r($dupArray);
Result
Array
(
[0] => 2
)
Explanation
Using array_count_values will count all the values of an array, which would look like:
Array
(
[1] => 1
[2] => 2
[3] => 1
)
Array
(
[1] => 1
[2] => 1
[3] => 1
[4] => 1
)
We then iterate through each array_count_values to locate values that occur more than once. This will work when you have more than one set of duplicate values:
$array1 = array(1, 2, 2, 3);
$array2 = array( 1, 2, 3, 4, 3);
Result
Array
(
[0] => 2
[1] => 3
)
While it may be less elegant, the simple way to do this is with a for loop:
$diff_array = array();
for ($i = 0; ($i < count($array1)) and ($i < count($array2)); $i++)
{
if ($array1[$i] !== $array2[$i]) { $diff_array[$i] = $array1[$i]; }
}

Categories