PHP-ILooping an arrays values through a larger array - php

I want to know if it is possible to take an array and insert the array's values into a bigger array, multiple times, so that the values of the smaller array fill up the bigger array.
Say array1 has values ([0 => 'a'],[1 => 'b'],[2 => 'c']), and array2 can hold 8 values. So, how would I take the values of array1 and insert them into array2 continuously until array2 runs out of space, so that array2 would have the values 'a','b','c','a','b','c','a','b'?
Thanks in advance,
~Hussain~

Essentially, you want to loop over and over the small array, adding each element to the new array until it has reached the desired size.
Consider this:
$max = 8;
$Orig_Array = array('a', 'b', 'c');
$Next_Array = array();
while True
{
foreach($Orig_Array as $v)
{
$Next_Array[] = $v;
if(count($Next_Array) >= $max)
break 2;
}
}

Assuming that your input array is indexed sequentially:
$len = count($input);
$output = array();
for ($i = 0; $i < MAX_SIZE; ++$i)
$output[] = $input[$i % $len];

$a = array('a','b','c');
$desired = 8;
$b = array();
for($i=0;$i<($desired/count($a))+1;++$i) $b = array_merge($b,$a);
array_splice($b,$desired);
Or
$a = array('a','b','c');
$desired = 8;
$b = array();
for($i=0;$i<$desired/count($a);++$i) $b = array_merge($b,$a);
for($i=0;$i<($desired-count($b)-1);++$i) $b[] = $a[$i];
The first one fills up an array so that it has at least desired number of elements and cuts off the rest. The second one fills up an array up the desired number of elements modulo original array size and adds up the rest.

Here's one using the input array's internal pointer, to keep things conceptually simple:
$input = array(1, 2, 3);
$size = 32;
$output = array();
for ( $i = 0; $i < $size; $i++ ) {
$curr = current($input);
if ( $curr === false ) {
reset($input);
$curr = current($input);
}
$output[] = $curr;
next($input);
}
print_r($output);die;

Related

PHP array comparision error

I have 2 SELECT statement in my PHP. Both the select statements fetch data from two different DB. The fetched data is saved in PDO Assoc Array. The problem is when I want to compare those two arrays to find that if the column 'id' exist in both arrays or not. If it exists then ignore it. If it's a unique id then save it into a third array. But I found some problems in my Logic Below
And after running the below code I am getting a couple of error:
1: Array to string conversion
2: duplicate key value violates unique constraint
$arr1 = $msql->fetchAll(PDO::FETCH_ASSOC);
$array1 = array();
foreach($arr1 as $x){
$array1[] = $x['id'];
}
$arr2 = $psql->fetechAll(PDO::FETCH_ASSOC);
$array2 = array();
foreach($arr2 as $y){
$array2[] = $y['id'];
}
$finalarray = array();
for ($i = 0; $i < count($arr1); $i++){
if(count(array_intersect($array1,$array2)) <= 1){// is the count of id is 1 or less save that whole row in the $finalarray
$finalarray = $arr1[$i]; // saving the unique row.
}
else{
continue;
}
}
All I am trying to get the unique row of data array() after comparing their id column.
You can use in_array() function as both arrays are index array.
$finalarray = array();
for ($i = 0; $i < count($arr1); $i++){
if(count(array_intersect($array1,$array2)) <= 1){// is the count of id is 1 or less save that whole row in the $finalarray
$finalarray = $arr1[$i]; // saving the unique row.
}
else{
continue;
}
}
make change in code:
$finalarray = array();
for ($i = 0; $i < count($arr1); $i++){
if(!in_array($array1[$i], $array2)){
$finalarray[] = $array1[$i]; // saving the unique row.
}
}
You can simply use array_intersect() to get common values between two array. for difference, can use array_diff()
$array1 = [1,2,3,4,5,6,7];
$array2 = [2,4,6];
//array_intersect — Computes the intersection of arrays
$result = array_intersect($array1, $array2);
print_r($result);
//array_diff — Computes the difference of arrays
$result = array_diff($array1, $array2);
print_r($result);
DEMO
Rather than using 3 different arrays to get unique ids, you can do it by using one array. Make changes to your code as below:
$finalarray = array();
$arr1 = $msql->fetchAll(PDO::FETCH_ASSOC);
foreach($arr1 as $x){
if (!in_array($x['id'],$finalarray)) { // check id is already stored or not
$finalarray[] = $x['id'];
}
}
$arr2 = $psql->fetechAll(PDO::FETCH_ASSOC);
foreach($arr2 as $y){
if (!in_array($y['id'],$finalarray)) { // check id is already stored or not
$finalarray[] = $y['id'];
}
}
Maybe you should make sure which array is larger before your loop ;
Or using array_diff:
$finalarray = array_diff($array1 , $array2) ?? [];
$finalarray = array_merge( array_diff($array2 , $array1) ?? [], $finalarray );

Efficiently pick n random elements from PHP array (without shuffle)

I have the following code to pick $n elements from an array $array in PHP:
shuffle($array);
$result = array_splice($array, 0, $n);
Given a large array but only a few elements (for example 5 out of 10000), this is relatively slow, so I would like to optimize it such that not all elements have to be shuffled. The values must be unique.
I'm looking fo the most performant alternative. We can assume that $array has no duplicates and is 0-indexed.
$randomArray = [];
while (count($randomArray) < 5) {
$randomKey = mt_rand(0, count($array)-1);
$randomArray[$randomKey] = $array[$randomKey];
}
This will provide exactly 5 elements with no duplicates and very quickly. The keys will be preserved.
Note: You'd have to make sure $array had 5 or more elements or add some sort of check to prevent an endless loop.
This function performs a shuffle on only $n elements where $n is the number of random elements you want to pick. It will also work on associative arrays and sparse arrays. $array is the array to work on and $n is the number of random elements to retrieve.
If we define the $max_index as count($array) - 1 - $iteration.
It works by generating a random number between 0 and $max_index. Picking the key at that index, and replacing its index with the value at $max_index so that it can never be picked again, as $max_index will be one less at the next iteration and unreachable.
In summary this is the Richard Durstenfeld's Fisher-Yates shuffle but operating only on $n elements instead of the entire array.
function rand_pluck($array, $n) {
$array_keys = array_keys($array);
$array_length = count($array_keys);
$max_index = $array_length -1;
$iterations = min($n, $array_length);
$random_array = array();
while($iterations--) {
$index = mt_rand(0, $max_index);
$value = $array_keys[$index];
$array_keys[$index] = $array_keys[$max_index];
array_push($random_array, $array[$value]);
$max_index--;
}
return $random_array;
}
The trick is to use a variation of shuffle or in other words a partial shuffle.
performance is not the only criterion, statistical efficiency, i.e unbiased sampling is as important (as the original shuffle solution is)
function random_pick( $a, $n )
{
$N = count($a);
$n = min($n, $N);
$picked = array_fill(0, $n, 0); $backup = array_fill(0, $n, 0);
// partially shuffle the array, and generate unbiased selection simultaneously
// this is a variation on fisher-yates-knuth shuffle
for ($i=0; $i<$n; $i++) // O(n) times
{
$selected = mt_rand( 0, --$N ); // unbiased sampling N * N-1 * N-2 * .. * N-n+1
$value = $a[ $selected ];
$a[ $selected ] = $a[ $N ];
$a[ $N ] = $value;
$backup[ $i ] = $selected;
$picked[ $i ] = $value;
}
// restore partially shuffled input array from backup
// optional step, if needed it can be ignored, e.g $a is passed by value, hence copied
for ($i=$n-1; $i>=0; $i--) // O(n) times
{
$selected = $backup[ $i ];
$value = $a[ $N ];
$a[ $N ] = $a[ $selected ];
$a[ $selected ] = $value;
$N++;
}
return $picked;
}
NOTE the algorithm is strictly O(n) in both time and space, produces unbiased selections (it is a partial unbiased shuffling) and produces output which is proper array with consecutive keys (not needing extra array_values etc..)
Use example:
$randomly_picked = random_pick($my_array, 5);
// or if an associative array is used
$randomly_picked_keys = random_pick(array_keys($my_array), 5);
$randomly_picked = array_intersect_key($my_array, array_flip($randomly_picked_keys));
For further variations and extensions of shuffling for PHP:
PHP - shuffle only part of an array
PHP shuffle with seed
How can I take n elements at random from a Perl array?
This will only show benifits for small n compared to an array shuffle, but you could
Choose a random index r n times, each time decreasing the limit by 1
Adjust for previously used indices
Take value
Store used index
Pseudocode
arr = []
used = []
for i = 0..n-1:
r = rand 0..len-i
d = 0
for j = 0..used.length-1:
if r >= used[j]:
d += 1
arr.append($array[r + d])
used.append(r)
return arr
You could generate n-times a random number with mt_rand() and then fill these values in a new array. To go against the case where the same index gets returned twice we use the actual returned index to fill the new array and check always if the index exists in the new array, if so we use while to loop through it as long as we get a duplicate index. At the end we use array_values() to get a 0-indexed array.
$count = count($array) - 1;
$new_array = array();
for($i = 0; $i < $n; $i++) {
$index = mt_rand(0, $count);
while(isset($new_array[$index])) {
$index = mt_rand(0, $count);
}
$new_array[$index] = $array[$index];
}
$new_array = array_values($new_array);
I wonder why everyone here make it so complicated?
Here's the fastest and simplest way:
$randomArray = array_rand(array_flip($array), $n);

PHP put several arrays in one separated by ","

I have some arrays extracted from a XML-file. These are in
$array0 = (.......)
$array1 = (.......)
...
$arrayN = (.......)
Now I need a single array with all arrays in it separated by "," as
$masterArray = array($array0,
$array1,
...
$arrayN)
I tried
for ( $i = 0; $i < N; $i++) {
$masterArray = $masterArray + $array[$i];
}
with no result. I tried array_merge but this will give one
$masterArray(......................all items of all $arrays.....)
How can I do it right?
for ( $i = 0; $i < N; $i++) {
$temp = "array".$i;
$masterArray[$i] = ${$temp};
}
Given your exact definition of what you got and what you want the routine should be:
for ( $i = 0; $i < N; $i++) $masterArray[] = ${'array'.$i};
Not much to explain here. You make a new entry in an array with $variable[] = <entry>; and you access your numbered array with a variable variable, see:
http://php.net/manual/en/language.variables.variable.php
I guess you wont to create a multi dimension array:
$masterArray = array();
$masterArray[] = $array0;
$masterArray[] = $array1;
...
$masterArray[] = $arrayN;
this will in all arrays as element of the MasterArray:
$masterArray[0=>(....),1=>(....), ...];
Then access it like this:
$arr1_key1 = $masterArray[1]['key1'] ; //$array1['key1'];
You can add specific keys if you wont:
$masterArray['arr1'] = $array1;
$arr1_key1 = $masterArray['arr1']['key1'] ; //$array1['key1']
In general read some more to get better understanding on how to work with arrays ;)

Given an array of integers, what's the most efficient way to get the number of other integers in the array within n?

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

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

Categories