divide array into smaller arrays [duplicate] - php

This question already has answers here:
How to get sub array in PHP?
(3 answers)
Closed 9 years ago.
I have an first $array1 of 200 integer values,$array1 integer values are random values and second array say as below
$array2= array('30','40,'70','30','30');
Both the arrays are generating dynamically.
I want to divide my $array1 into smaller arrays as per $array2 values, as first 30 integers from $array1 will make separate array, later 40 intergers from $array1 will make second new array and so on. From above example there will be 5 new arrays.
Can anyone please help me.
I tried below below it can just divide based on values assigned. But it is not useful
$arrays = array_chunk($array1, 30);

You should iterate over the array of chunk sizes and cut off an appropriate portion of your input array each time:
$input = range(0, 199);
$chunks = array(30, 40, 70, 30, 30);
$output = array();
$processed = 0;
while($chunks) {
$processed += $size = array_shift($chunks);
$output[] = array_slice($input, $processed, $size);
}

Why do not you try this
$startingPoint = 0;
foreach($array2 as $val)
{
for($i = $startingPoint ; $i < $startingPoint + $val ; $i++)
{ $array1[$i] }
$startingPoint += $val
}

Related

shuffle an array with a "limit" in PHP

What I try to achieve: randomize the order of all elements in an array, but allow each element to change its position only by a limited number of "steps".
Say I have an array like below, and I wish to randomize with a limit of 2 steps:
$array = [92,12,2,18,17,88,56];
An outcome could be: [2,12,92,17,18,56,88] (all elements of the array moved a maximum of 2 steps), but it could not be: [56,92,2,12,17,18,88] because in this example 56 moved too far.
I considered using a combination of array_chunk and shuffle, but this is problematic because elements will be shuffled inside their chunk, resulting in elements at the beginning or end of a chunk only moving in one direction. This is what I came up with (and problematic):
// in chunks of 3 an element can move a max. of 2 steps.
$chunks = array_chunk($array, 3);
$newChunks = [];
foreach ($chunks as $chunk){
$keys = array_keys($chunk);
shuffle($keys);
$newChunk = [];
foreach ($keys as $key){
$newChunk[$key] = $chunk[$key];
}
$newChunks[] = $newChunk;
}
Another idea I had was to get the key of the item in the array and with rand add of subtract my limit. For example:
foreach ( $array as $key => $value ) {
$newArray[] = ["key" => $key+rand(-2,2), "value" => $value];
};
This creates a new array with each of its elements being an array with the original value plus a value key that is the original key plus or minus 2. I could flatten this array, but the problem with this is that I can have duplicate keys.
I created this function to do this, but I guess it needs more improvements:
/**
* #param array $array
* #param int $limit
* #return array
*/
function shuffleArray(array $array, int $limit): array
{
$arrayCount = count($array);
$limit = min($arrayCount, $limit);
for ($i = 0; $i < $limit; $i++) {
for ($j = 0; $j < $arrayCount;) {
$toIndex = min($arrayCount - 1, $j + rand(0, 1));
[$array[$j], $array[$toIndex]] = [$array[$toIndex], $array[$j]];
$j += (($toIndex === $j) ? 1 : 2);
}
}
return $array;
}
Test:
$array = [92, 12, 2, 18, 17, 88, 56];
$limit = 2;
$result = shuffleArray($array, $limit); // [12, 92, 17, 2, 18, 56, 88]
Here is a possible solution in one pass :
Try to swap each element at position i with an element between i (stay in place) and i+x. I look only forward to avoid swaping an element several times. And I need an extra array to flag the already swapped elements. I don't need to process them in the future as they were already moved.
function shuffle_array($a, $limit)
{
$result = $a ;
$shuffled_index = array() ; // list of already shuffled elements
$n = count($result);
for($i = 0 ; $i < $n ; ++$i)
{
if( in_array($i, $shuffled_index) ) continue ; // already shuffled, go to the next elements
$possibleIndex = array_diff( range($i, min($i + $limit, $n-1)), $shuffled_index) ; // get all the possible "jumps", minus the already- shuffled index
$selectedIndex = $possibleIndex[ array_rand($possibleIndex) ]; // randomly choose one of the possible index
// swap the two elements
$tmp = $result[$i] ;
$result[$i] = $result[$selectedIndex] ;
$result[$selectedIndex] = $tmp ;
// element at position $selectedIndex is already shuffled, it needs no more processing
$shuffled_index[] = $selectedIndex ;
}
return $result ;
}
$array = [92,12,2,18,17,88,56];
$limit = 2 ;
shuffle_array($array, $limit); // [2, 18, 92, 12, 17, 56, 88]
I expect more elements to stay in place than in the solution of Kerkouch, as some elements can have very few remaining free choices.

create transpose matrix using php [duplicate]

This question already has answers here:
Transposing multidimensional arrays in PHP
(12 answers)
Closed 2 years ago.
For example if a matrix is:
1 2
3 4
5 6
Then transpose of above matrix will be:
1 3 5
2 4 6
This is my current code:
<?php
// transpose matrix
$trans = array(
array(1, 2),
array(3, 4),
array(5, 6)
);
foreach ($trans as $key => $val){
foreach ($trans[$key] as $k => $v){
echo $v;
}
}
?>
There's a quirky PHP way to transpose a 2d array:
$trans = array(
array(1, 2),
array(3, 4),
array(5, 6)
);
array_unshift($trans, null);
$trans = call_user_func_array('array_map', $trans);
var_dump($trans);
Demo
EDIT Easier approach using PHP 5.6 array unpacking
With the introduction of the array argument unpacking feature in PHP 5.6, we can simplify this still further:
$trans = array(
array(1, 2),
array(3, 4),
array(5, 6)
);
$trans = array_map(null, ...$trans);
var_dump($trans);
EDIT Explanation
Quoting from the PHP docs for the array_map() function:
An interesting use of this function is to construct an array of arrays, which can be easily performed by using NULL as the name of the callback function
(See Example #4 from that docs page for an example of what this does)
The array_unshift($trans, null) that we perform first is providing that NULL callback, and we use call_user_func_array() because we don't necessarily know how many values there are in our $trans array. What we're doing using that call_user_func_array() is the equivalent of:
$trans = array_map(NULL, $trans[0], $trans[1], $trans[2]);
for your example array, because the top-level of your 2-d array has three elements (keys 0, 1 and 2).
Effectively, this NULL callback loops through all the arrays in parallel taking each value from them in turn to build a new array:
$maxArraySize = max(count($array[0], $array[1], $array[2]);
// $maxArraySize will have a value of 2 in your case,
// because your sub-arrays are all equal size
$newArray = [];
for($i = 0; $i < $maxArraySize; ++$i) {
$tmpArray = [];
$tmpArray[] = $array[0][$i];
$tmpArray[] = $array[1][$i];
$tmpArray[] = $array[2][$i];
$newArray[] = $tmpArray[];
}
There's a couple of extra checks in there
it doesn't care if your arrays are associative or enumerated in either dimension, because it accesses the $ith element, not the index
If the sub-arrays aren't all the same length, then it effectively pads the shorter sub-arrays with null values to match the length of the longest
It doesn't matter how many arrays you pass in, it will work with them all in parallel
I believe this works with rectangular arrays as well.
The trick: return array_map(null, ...$squareArray); seems to work in an unexpected way for a single column array
function RotateSquare2DArray($squareArray)
{
if ($squareArray == null) { return null; }
$rotatedArray = array();
$r = 0;
foreach($squareArray as $row) {
$c = 0;
if (is_array($row)) {
foreach($row as $cell) {
$rotatedArray[$c][$r] = $cell;
++$c;
}
}
else $rotatedArray[$c][$r] = $row;
++$r;
}
return $rotatedArray;
}
If the array is associative, I use this
function RotateSquareAssociativeArray($squareArray)
{
if ($squareArray == null) { return null; }
$rotatedArray = array();
$r = 0;
foreach($squareArray as $c=>$row) {
if (is_array($row)) {
foreach($row as $key=>$cell) {
$rotatedArray[$key][$c] = $cell;
}
}
else {
$rotatedArray[$c][$r] = $row;
}
++$r;
}
return $rotatedArray;
}

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

Merging 2 Arrays [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Combing 3 arrays into one array
I have the following arrays:
$front = array("front_first","front_second");
$back = array("back_first", "back_second", "back_third","back_fourth");
what I'm trying to do is merge them so an output like this would result:
$final = array(
"back_first",
"front_first",
"back_second",
"front_second",
"back_third",
"front_second",
"back_fourth",
"front_second"
);
How can I have it repeat the last value in the shortest array so that it can combine into one $final[] with no empty values?.
php's array_merge
$final = array_merge($front, $back);
and maybe a combination with array_pad?
$front = array_pad($front, count($back)-1, 'second_front');
$final = array_merge($front, $back);
The first bit is easy, just use array_merge() to construct your combined array.
The second bit requires arbitrary sorting and therefore will require use of usort() to sort the array according to rules you implement in the callback function.
Is the order really important?
Working Codepad - bgIYz9iw
$final = array();
for( $i = 0; $i < 4; $i++ ) {
if( $i > 1 ) {
$final[] = $back[$i];
$final[] = $front[1];
}
else {
$final[] = $back[$i];
$final[] = $front[$i];
}
}

Slice an array into 4 other arrays

I have an array which I want to slice in 4 other arrays because I want to display the content of the first array on four columns.
I have tried the code above, but what I get is N columns with 4 items.
$groups = array();
for ($i = 0; $i < count($menu); $i += 4) $groups[] = array_slice($menu, $i, 4);
Can this be modified in order to get exactly 4 columns and distribute the values so they fit?
Like Michael Berkowski suggested:
$groups = array_chunk($menu,4);
Should give you what you need. If you're more into "manual labour":
$groups = array();
while($groups[] = array_splice($menu,0,4))
{//no need for any code here ^^ chunks the array just fine
printf('This loop will run another %d times<br/>',(int)ceil(count($menu)/4));
}
Update:
I see I got this a bit wrong... want to chunk into 4 arrays, not into arrays of four:
$groups = array_chunk($menu,(int)ceil(count($menu)/4));
You can try
// Some Random array
$array = range(1, 20);
// Split it 4 Chuncks
$array = array_chunk($array, 4);
// Slice The first 4 Chunks
$array = array_slice($array, 0, 4);
// Output Result
foreach ( $array as $set ) {
printf("<li>%s</li>", implode(",", $set));
}

Categories