I have an array of n elements and I need to get random 20% of those elements into another array. Is there any function which can achieve this?
Currently what I can think of is this:
foreach ($orders as $order) {
if (rand(1, 100) > 80) {
echo('20%');
} else {
echo('80%');
}
}
Is there a more optimal way?
You could shuffle the array and then take the first 20% elements.
$array = [1, 2, 3, 4];
shuffle($array);
$twenty = array_slice($array, 0, floor(count($array) / 5));
$eighty = array_slice($array, floor(count($array) / 5));
The simplest solution is probably to use shuffle:
shuffle($orders);
for ($i = 0; $i < count($orders) / 5; $i++) {
// do something with the first 20% of elements
}
for (; $i < count($orders); $i++) {
// do something with the rest of the array
}
To get two arrays by one function call, use array_splice function. After
shuffle($array);
$twenty = array_splice($array, floor(count($array) / 5 * 4));
$twenty will held 1/5 of source array and $array - other items
Shuffle is the simplest solution for this case
$array = [1,2,3,4]
shuffle($array);
$firstSlice = array_slice($array , 0 , count($array)/2);
$secondSlice = array_slice($array , count($array)/2 , count($array));
Related
I have two arrays which I want to multiply and get the final sum. First one is fixed but the second one could have missing elements. For example:
$array1 = array(1, 2, 3, 4, 5);
$array2 = array(1, 3, 5);
Lets say I've got missing elements $array2[1] and $array2[3]. I want to be able to multiply and sum up the rest as:
$sum = array_sum($array1[0] * $array2[0] + $array1[1] * $array2[1] + $array1[2] * $array2[2] + $array1[3] * $array2[3] + $array1[4] + $array2[5]);
Length of arrays may also vary so can't do it the way I've written it above. Any suggestions?
You can complete the array2 missing values as 1, then make the two array have the same length.
$missingKeys = [1,3];
foreach($missingKeys as $k)
{
$array2[$k] = 1;
}
$sum = 0;
foreach($array1 as $k => $v)
{
$sum += $v * $array1[$k];
}
Ok, I didn't use my own advise, but I think this might work?
$total = 0;
foreach ($array1 as $index => $value)
{
if (isset($array2[$index])) $total += $value*$array2[$index];
else $total += $value;
}
echo $total;
The assumption is that all elements of $array2 are present in $array1, but not necessarily the other way around.
As you wrote in your question that the first array is leading (has all the indexes) you only need to iterate over it and eventually multiply with the value from the second array or one:
$sum = 0;
foreach ($array1 as $k => $v) {
$sum += $v * ($array2[$k] ?? 1);
}
Different to the accepted answer, there is no need to manipulate the second array.
If I understood your question properly, and your looking for array multiplication, you could use 2 for loops, iterating one of them and multiplying. Your probably looking for something like this:
for ($i = 0; $i < count($array1); $i++) {
for ($j = 0; $j < count($array2); $j++) {
$sum += $array1[$i] * $array2[$j];
}
}
Given the following array:
$arr = array(0,0,1,2,2,5,6,7,7,9,10,10);
And assuming $n = 2, what is the most efficient way to get a count of each value in the array within $n of each value?
For example, 6 has 3 other values within $n: 5,7,7.
Ultimately I'd like a corresponding array with simply the counts within $n, like so:
// 0,0,1,2,2,5,6,7,7,9,10,10 // $arr, so you can see it lined up
$count_arr = array(4,4,4,4,4,3,3,4,4,4, 2, 2);
Is a simple foreach loop the way to go? CodePad Link
$arr = array(0,0,1,2,2,5,6,7,7,9,10,10);
$n = 2;
$count_arr = array();
foreach ($arr as $v) {
$range = range(($v-$n),($v+$n)); // simple range between lower and upper bound
$count = count(array_intersect($arr,$range)); // count intersect array
$count_arr[] = $count-1; // subtract 1 so you don't count itself
}
print_r($arr);
print_r($count_arr);
My last answer was written without fully groking the problem...
Try sorting the array, before processing it, and leverage that when you run through it. This has a better runtime complexity.
$arr = array(0,0,1,2,2,5,6,7,7,9,10,10);
asort($arr);
$n = 2;
$cnt = count($arr);
$counts = array_pad(array(), $cnt, 0);
for ($x=0; $x<$cnt; $x++) {
$low = $x - 1;
$lower_range_bound = $arr[$x]-$n;
while($low >= 0 && ($arr[$low] >= $lower_range_bound)) {
$counts[$x]++;
$low--;
}
$high = $x + 1;
$upper_range_bound = $arr[$x]+$n;
while($high < $cnt && $arr[$high] <= $upper_range_bound) {
$counts[$x]++;
$high++;
}
}
print_r($arr);
print_r($counts);
Play with it here: http://codepad.org/JXlZNCxW
I need to calculate the average increase of array values, and I've made a little script which works, but I'd like to know if:
There is a better, more efficient way of doing this
My logic is correct here in calculating the average increase
Lets say I have an array like so:
$array = array(5,10,15,10,0,15);
Lets also imagine that each array item is 1 day, and the value is some counter for that day. I would like to calculate the average increase/decrease in the counter.
What I've done, is looped through the array, and altered the values so that the current item = current item - previous item, what way I'm left with an array which would look like so:
$array = array(5,5,-5,-10,15);
Then I calculate the average as per normal, which in this example would give me a 2 average increase on a daily basis.
Code here:
$array = array(5,10,15,10,0,15);
$count = count($array);
for($i=0;$i<$count;$i++) {
if($i==0) {
$value = $array[$i];
unset($array[$i]);
}
else {
$tmp = $array[$i];
$array[$i] -= $value;
$value = $tmp;
}
}
echo array_sum($array) / count($array);
Is the logic correct here, and is there a more efficient way of doing this, maybe without the loop?
Thanks in advance :)
EDIT: Updated code to account for excluding first value
How about this:
function moving_average($array) {
for ($i = 1; $i < sizeof($array); $i++) {
$result[] = $array[$i] - $array[$i-1];
}
return array_sum($result)/count($result);
}
Try this :
$array = array(5,10,15,10,0,15);
$array2 = $array;
array_pop($array2);
array_unshift($array2, $array[0]);
$subtracted = array_map(function ($x, $y) { return $y-$x; } , $array2, $array);
array_shift($subtracted); /// Comment this if you want six values with 0 as first value
echo array_sum($subtracted) / count($subtracted);
Here's a snazzy one-liner for you:
$days = array(5, 10, 15, 10, 0, 15);
$deltas = array_slice(array_map(function($day1, $day2) {
return $day2 - $day1;
}, $days, array_slice($days, 1)), 0, -1);
var_dump(array_sum($deltas) / count($deltas));
$array = array(5,10,15,10,0,15);
list($prevVal) = array_slice($array, 1);
array_walk($array, function($value, $key, &$prevVal) use(&$array){
if ($key==0) { return; }
$array[$key] = ($value - $prevVal);
$prevVal = $value;
}, $prevVal);
echo array_sum($array) / count($array);
Outputs 1.6666666666667 in float(3.0994415283203E-5)
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).
How can you convert the following code to PHP?
summat = [sum(arra[i:i+4]) for i in range(0,len(arra),4)]
My attempt
$summat = array()
foreach ( range(0, $arra.length, 4) as $i) {
$summat = array ( array_sum( array_slice( $array, $i, $i+5) ) ) // don't know how to append the sums the array
$sum = array();
foreach(range(0, count($a), 4) as $i)
$sum []= array_sum(array_slice($a, $i, 4));
"[]=" is an append-to-array operator
slice's second parameter is slice length, not the last index
or even simpler
$sum = array_map('array_sum', array_chunk($a, 4));
To append a value to an array, use:
$summat[] = array_sum(...);
The PHP way of doing ranges is similar to the C way:
for($i = 0; $i < count($arra); $i += 4) {
// ...
}