Related
I have long string which I split after each 4th char. After that I want to take 3 random of them and show how many times are in the array.
What I have is
$string = "AAAAAAABAAACAAADAAAEAAAFAAAGAAAHAAAIAAAJAAAKAAALAAAMAAANAAAOAAAPAAAQAAARAAASAAATAAAUAAAVAAAWAAAXAAAYAAAZAAAaAAAbAAAcAAAdAAAeAAAfAAAgAAAhAAAiAAAjAAAkAAAlAAAmAAAnAAAoAAApAAAqAAArAAAsAAAtAAAuAAAvAAAwAAAxAAAyAAAzAABAAABBAABCAABDAABEAABFAABGAABHAABIAABJAABKAABLAABMAABNAA";
$segmentLength = 3;
$totalLength = strlen($string);
for ($i = 0; $i < $totalLength; $i += $segmentLength) {
$result[] = substr($string, min($totalLength - $segmentLength, $i), $segmentLength);
}
print_r(array_rand(array_count_values($result), 4));
array_count_values($result) output is
Array
(
[AAA] => 19
[ABA] => 1
[AAC] => 1
........
[AAL] => 1
[MAA] => 1
[AAB] => 4
)
I'm trying with print_r(array_rand(array_count_values($result), 4)); to output
Array
(
[AAA] => 19
[ABA] => 1
[AAC] => 1
[AAB] => 4
)
or
Array
(
[ABA] => 1
[AAC] => 1
[AAL] => 1
[MAA] => 1
)
instead I get
Array
(
[0] => AHA
[1] => AAa
[2] => zAA
[3] => BGA
)
...
Array
(
[0] => GAA
[1] => AxA
[2] => CAA
[3] => BGA
)
... so on
You could store the result of array_count_values($result); to a variable and then get a random set of keys from that result. Then loop through that random list of keys and generate your desired output. For example:
$string = "AAAAAAABAAACAAADAAAEAAAFAAAGAAAHAAAIAAAJAAAKAAALAAAMAAANAAAOAAAPAAAQAAARAAASAAATAAAUAAAVAAAWAAAXAAAYAAAZAAAaAAAbAAAcAAAdAAAeAAAfAAAgAAAhAAAiAAAjAAAkAAAlAAAmAAAnAAAoAAApAAAqAAArAAAsAAAtAAAuAAAvAAAwAAAxAAAyAAAzAABAAABBAABCAABDAABEAABFAABGAABHAABIAABJAABKAABLAABMAABNAA";
$segmentLength = 3;
$totalLength = strlen($string);
for ($i = 0; $i < $totalLength; $i += $segmentLength) {
$result[] = substr($string, min($totalLength - $segmentLength, $i), $segmentLength);
}
$countedValues = array_count_values($result);
$randValues = array_rand($countedValues, 4);
$output = [];
for ($i = 0; $i < count($randValues); $i++) {
$key = $randValues[$i];
$output[$key] = $countedValues[$key];
}
print_r($output);
I am trying to split an array of items into multiple equal parts with a maximum of 6 items per array
for example:
5 items in original array --> result: 1 array with 5 items
12 items in original array --> result: 2 arrays with 6 items
7 items in original array --> result: 2 arrays with 3 and 4 items
13 items in original array --> result: 3 arrays with 5,4,4 items
I have absolutely no idea how to get started on this
I guess this is what you are looking for. Not exactly beautiful, but working:
<?php
$size = 13;
$step = 6;
$input = array_keys(array_fill(0, $size, null));
$count = ceil($size / $step);
$chunk = floor($size / $count);
$bonus = $size % $count;
for ($i = 0; $i < $count; $i++) {
$output[] =
$i == 0 ?
array_slice($input, $i * $chunk, $chunk + $bonus) :
array_slice($input, $i * $chunk + $bonus, $chunk);
}
print_r($output);
Here $size is the size of your array and $step is the size of the chunks cut from that array. You can play around with those values.
An example output with the settings above would be:
Array
(
[0] => Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 3
[4] => 4
)
[1] => Array
(
[0] => 5
[1] => 6
[2] => 7
[3] => 8
)
[2] => Array
(
[0] => 9
[1] => 10
[2] => 11
[3] => 12
)
)
Ok, I did this with a more dynamic programming way, where in we compute the distribution for smaller subproblems and go from 6 to 1, to see if current $j in the code fits in any of the previous distribution.
<?php
$arr = [];
$size = rand(1,150);
$range = range(1,$size);
$dist = [];
$dist[] = [];
for($i=1;$i<=$size;++$i){
if($i <= 6) $dist[] = [$i];
else{
for($j=6;$j>=1;--$j){
if(abs($j - $dist[$i-$j][0]) <= 1){
$dist[] = array_merge($dist[$i-$j],[$j]);
break;
}
}
}
}
// echo $size,PHP_EOL;
// print_r($dist[$size]); print the distribution if you want.
$result = [];
$curr_index = 0;
foreach($dist[$size] as $chunk_size){
$result[] = array_slice($range,$curr_index,$chunk_size);
$curr_index += $chunk_size;
}
echo $size,PHP_EOL;
print_r($result);
Demo: https://3v4l.org/gCWB2 (Note that the output there is different for each version of PHP as a different random number of an array size is generated each time).
Update: You can further optimize the above code for this heavy line $dist[] = array_merge($dist[$i-$j],[$j]);, but this I leave as an exercise to you(hint: store only the smallest starting one with it's count).
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 );
Hi i am trying to create a sub array from an array.i.e; think I have an array such as given below
$array = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}
which I explode and assign it to a variable $i..
and run the for loop as shown below..
for ( $i=0;$i<count($array);$i++) {
$a = array();
$b = $array[$i];
for($j=0;$j<count($array);$j++){
if($b != $array[$j]){
$a[] = $array[$j];
}
}
the output I want is when
$i = 1
the array should be
{2,3,4,5,6,7,8,9,10,11}
and when
$i = 2
the array should be
{3,4,5,6,7,8,9,10,11,12}
similarly when
$i=19
the array should be
{1,2,3,4,5,6,7,8,9,10}
so how can I do it.
Assuming $i is supposed to be an offset and not the actual value in the array, you can do
$fullArray = range(1, 19);
$i = 19;
$valuesToReturn = 10;
$subset = iterator_to_array(
new LimitIterator(
new InfiniteIterator(
new ArrayIterator($fullArray)
),
$i,
$valuesToReturn
)
);
print_r($subset);
This will give your desired output, e.g.
$i = 1 will give 2 to 11
$i = 2 will give 3 to 12
…
$i = 10 will give 11 to 1
$i = 11 will give 12 to 2
…
$i = 19 will give 1 to 10
$i = 20 will give the same as $i = 1 again
and so on.
$array = range(1, 19);
$i = 19;
$result = array();
$after = array_slice($array, $i, 10);
$before = array_slice($array, 0, 10 - count($after));
$result = array_merge($after, $before);
var_dump(json_encode($result));
P.S. please note 0 element has 1 value and so on...
for ($i = 0; $i < count($array); $i++) {
if ($i + 10 < count($array))
$a = array_slice($array, $i, 10);
else
$a = array_merge(array_slice($array, $i), array_slice($array, 0, 10-(count($array)-$i)));
// do something with $a before it is over-written on the next iteration
}
This test:
<?php
$array = array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19);
for ($i = 0; $i < count($array); $i++) {
if ($i + 10 < count($array))
$a = array_slice($array, $i, 10);
else
$a = array_merge(array_slice($array, $i), array_slice($array, 0, 10-(count($array)-$i)));
echo "<h2>$i</h2>\n<pre>".print_r($a,true)."</pre><br />\n";
}
Resulted in this:
0
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
[5] => 6
[6] => 7
[7] => 8
[8] => 9
[9] => 10
)
...
9
Array
(
[0] => 10
[1] => 11
[2] => 12
[3] => 13
[4] => 14
[5] => 15
[6] => 16
[7] => 17
[8] => 18
[9] => 19
)
10
Array
(
[0] => 11
[1] => 12
[2] => 13
[3] => 14
[4] => 15
[5] => 16
[6] => 17
[7] => 18
[8] => 19
[9] => 1
)
...
18
Array
(
[0] => 19
[1] => 1
[2] => 2
[3] => 3
[4] => 4
[5] => 5
[6] => 6
[7] => 7
[8] => 8
[9] => 9
)
This works fine from my end
<?php
$array = array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19);
$size = sizeof($array); // Defining the array size
$str = 17; // This is the reference value from which you have to extract the values
$key = array_search($str, $array);
$key = $key+1; // in order to skip the given reference value
$start = $key%$size;
$end = $start+9;
for($i=$start; $i<=$end; $i++) {
$j = ($i%$size);
$result[] = $array[$j];
}
echo '<pre>'; print_r($result);
?>
It looks like all you need is a slice of a certain size from the array, slice that wraps around the array's end and continues from the beginning. It treats the array like a circular list.
You can achieve this in many ways, one of the simplest (in terms of lines of code) is to extend the original array by appending a copy of it at its end and use the PHP function array_slice() to extract the slice you need:
function getWrappedSlice(array $array, $start, $count = 10)
{
return array_slice(array_merge($array, $array), $start, $count);
}
Of course, you have to be sure that $start is between 0 and count($array) - 1 (including), otherwise the value returned by the function won't be what you expect.
Round-robin on an array can be achieved by doing a "rotate" operation inside each iteration:
for ($i = 0; $i < count($array); ++$i) {
// rotate the array (left)
array_push($array, array_shift($array));
// use $array
}
During the loop, the first element of the array is placed at the back. At the end of the loop, the array is restored to its original value.
I have the following:
Array
(
[0] => Array
(
[department] => Central>ACME>BusDev
[Total_Staff] => 4
[Total_Resp] => 0
)
)
There are over 150 of these within the array.
I can easily sum, for example, Total_Staff and Total_Resp using something like:
foreach($arr as $num => $values) {
$sum_staff += $values[ 'Total_Staff' ];
$sum_resp += $values[ 'Total_Resp' ];
}
However what I need to do is sum only elements of the array, for example I need to sum Total_Staff and Total_resp that lies between indexes 0 and 7 or 12 and 58.
Not sure how to go about this.
Is this what you need
foreach($arr as $num => $values) {
if(($num >= 0 && $num <= 7) || ($num >= 12 && $num <= 58))
$sum += $values[ 'Total_Staff' ];
}
Using a for loop would be the way to solve this:
$start = 12;
$end = 58;
$sum_total_staff = 0;
$sum_total_resp = 0;
for( $i = $start; $i <= $end; $i++ ) {
$sum_total_staff += $arr[$i]["Total_Staff"];
$sum_total_resp += $arr[$i]["Total_Resp"];
}
Id say use these 2 function to slice & merge the arrays. It will get 8 arrays from which are between indexes 0-7 (with 0 and 7 included) and same with the second one. If you want without 0 and 7, it would be with arguments 1, 6, so array_slide($arr, 1, 6); and so on.
$new_arr1 = array_slice($arr, 0, 8);
$new_arr2 = array_slice($arr, 12, 47);
$arr = array_merge($new_arr1, $new_arr2);