Split array into 4-element chunks then implode into strings - php

$array = [1, 2, 3, 4, 5, 6, 7, 8, 9];
I want output like
['1, 2, 3, 4', '5, 6, 7, 8', '9'];

You can use array_chunk() to split your array into chunks of 4 items. Then array_map() to implode() each chunk:
$array = [1, 2, 3, 4, 5, 6, 7, 8, 9];
$chunk = array_chunk($array, 4);
var_dump(array_map(fn($item) => implode(', ', $item), $chunk));
Outputs:
array(3) {
[0]=> string(7) "1, 2, 3, 4"
[1]=> string(7) "5, 6, 7, 8"
[2]=> string(1) "9"
}

you can do that
const $array = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const $chunk = $array.reduce((r,v,i)=>
{
if (!(i%4)) r.pos = r.resp.push(`${v}`) -1
else r.resp[r.pos] += `,${v}`
return r
}, { resp : [], pos:0 } ).resp
console.log( $chunk )

For best efficiency in terms of time complexity, loop over the array only once. As you iterate, divide the index by 4 and "floor" or "truncate" the dividend to form grouping keys.
When a grouping key is encountered more than once, prepend the delimiting comma-space before appending the new string value to the group's string.
Code: (Demo)
$array = [1, 2, 3, 4, 5, 6, 7, 8, 9];
foreach ($array as $i => $v) {
$group = (int) ($i / 4);
if (isset($result[$group])) {
$result[$group] .= ", $v";
} else {
$result[$group] = "$v";
}
}
var_export($result);
More concisely, you can split the array into 4-element rows and then implode those elements to form your delimited strings. This has more expensive time complexity because it iterates more times than the number of elements in the input array. (Demo)
var_export(
array_map(
fn($v) => implode(', ', $v),
array_chunk($array, 4)
)
);
You could also consume the input array as you isolate 4 elements at a time with array_splice(), but this is probably the least advisable since it eventually erases all of the data in the input array. (Demo)
$result = [];
while ($array) {
$result[] = implode(', ', array_splice($array, 0, 4));
}
var_export($result);
Output from all above techniques:
array (
0 => '1, 2, 3, 4',
1 => '5, 6, 7, 8',
2 => '9',
)

Related

How to remove unique elements within multidimensional array?

How to remove dulicate keys from multidimensional array?
My array is as follows:
$array = [[0, 1, 2, 3, 4], [1, 2, 3, 4, 6]];
My desired array should be:
$array = [[0, 1, 2, 3, 4], [6]];
Here's a quick and dirty solution for you:
Walk through every element of the array recursively and if you've not seen an element set it to null (unsetting it doesn't work for some reason). Then filter the resulting sub-arrays.
$array = [[0, 1, 2, 3, 4], [1, 2, 3, 4, 6]];
$seen = [];
array_walk_recursive($array, function (&$v) use (&$seen) {
if (!array_key_exists($v, $seen) {
$seen[$v] = true;
} else {
$v = null;
}
});
$final = array_map('array_filter', $array);
If the functions array_diff() and array_values​​() are used, the solution can be delivered in one line of code:
$array = [[0, 1, 2, 3, 4], [1, 2, 3, 4, 6]];
$array[1] = array_values(array_diff($array[1],$array[0]));
var_export($array);
Output:
array (
0 =>
array (
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => 4,
),
1 =>
array (
0 => 6,
),
)
$serialize=array_map('serialize',$array);
$unique=array_unique($serialize);
$result=array_map('unserialize',$uniue);
print_r($result);

How to get max element at each index while comparing two arrays?

I have two indexed arrays of identical length:
$first_array = [1,3,4,5,6];
$second_array = [5,2,1,7,9];
I need to generate a new array that consists of the higher value between the two elements at each index.
The output should be:
$output_array[5, 3, 4, 7, 9];
Super easy one-liner:
Pass both arrays to array_map(), as it synchronously loops through both sets of data, call max() on the two elements.
Code: (Demo)
$first_array = [1, 3, 4, 5, 6];
$second_array = [5, 2, 1, 7, 9];
var_export(array_map('max', $first_array, $second_array));
Output:
array (
0 => 5,
1 => 3,
2 => 4,
3 => 7,
4 => 9,
)
Try this way. demo
<?php
$first_array = array(1,3,4,5,6);
$second_array = array(5,2,1,7,9);
$return = array();
foreach($first_array as $key => $value){
if($first_array[$key] > $second_array[$key]){
$return[] = $first_array[$key];
}else{
$return[] = $second_array[$key];
}
}
print_r($return);

Sort an array of numbers by another predefined, non-exhaustive array of number, then sort ascending

Given two arrays $A1 and $A2, sort $A1 in such a way that the relative order among the elements will be same as those in $A2. For the elements not present in $A2, move them to the back of the array in ascending order.
$A1 = [2, 1, 2, 5, 7, 1, 9, 3, 6, 8, 8];
$A2 = [2, 1, 8, 3];
Desired output:
[2, 2, 1, 1, 8, 8, 3, 5, 6, 7, 9]
Coding attempt:
$sorted = array();
foreach($a1 as $key => $value) {
if(in_array($value, $a2)) {
$sorted[array_search($value, $a1)] = $value;
}
}
This can be done via for each loop :
$arr1 = array(2, 1, 2, 5, 7, 1, 9, 3, 6, 8, 8); // array to be sorted
$arr2 = array(2, 1, 8, 3); // refrence array for sort logic
// Output: A1[] = {2, 2, 1, 1, 8, 8, 3, 5, 6, 7, 9}
$sortarr = array(); // array to store final sorted values
foreach ($arr2 as $a) {
foreach ($arr1 as $k => $b) {
if($b==$a) {
$sortarr[]=$b;
unset($arr1[$k]);
}
}
}
$finalarr = array_merge($sortarr, $arr1);
print_r($finalarr);
You can use usort like this:
$k = array_flip($a2); // Create an associative array for the second array
usort($a1, function($a, $b) use ($k) {
return isset($k[$a]) ? (isset($k[$b]) ? $k[$a]-$k[$b] : -1) : (isset($k[$b]) ? 1 : $a-$b);
});
Other solutions that use a nested loop result in a time complexity of O(n²), while this has a time complexity of O(nlogn).
i tried this code and works:
<?php
/*
Input: A1[] = {2, 1, 2, 5, 7, 1, 9, 3, 6, 8, 8}
A2[] = {2, 1, 8, 3}
Output: A1[] = {2, 2, 1, 1, 8, 8, 3, 5, 6, 7, 9}
*/
$a1=array(2, 1, 2, 5, 7, 1, 9, 3, 6, 8, 8);
$a2=array(2, 1, 8, 3);
$a3=array();
sort($a1);//order array
//order array a3 with a2 value....
for($i=0;$i<sizeof($a2);$i++){
for($j=0;$j<sizeof($a1);$j++){
if($a1[$j]==$a2[$i]){
array_push($a3,$a2[$i]);
//if exsist value i change value in a1 in x
$a1[$j]="x";
}
}
}
//write in a3 the next number not present in a2
for($i=0;$i<sizeof($a1);$i++){
if($a1[$i]<>"x"){
array_push($a3, $a1[$i]);
}
}
print_r($a3);
//out:Array ( [0] => 2 [1] => 2 [2] => 1 [3] => 1 [4] => 8 [5] => 8 [6] => 3 [7] => 5 [8] => 6 [9] => 7 [10] => 9 )
?>
Hope this helps
I do not endorse the use of nested loops because they will be doing too many unnecessary cycles. #trincot's approach moreso represents what I would use in a professional application, but I will demonstrate a more modern and concise style with no iterated function calls.
Code: (Demo)
$arr1 = [2, 1, 2, 5, 7, 1, 9, 3, 6, 8, 8];
$arr2 = [2, 1, 8, 3];
$priority = array_flip($arr2);
$fallback = count($arr2);
usort(
$arr1,
fn($a, $b) =>
[$priority[$a] ?? $fallback, $a]
<=>
[$priority[$b] ?? $fallback, $b]
);
var_export($arr1);
// [2, 2, 1, 1, 8, 8, 3, 5, 6, 7, 9]
$arr2 is flipped into a lookup array, and count() is used when a value is not found in the lookup array. Whenever the first rule results in a tie, the second rule orders the numbers numerically in an ascending direction.
The meaning of custom function's syntax is:
[left value rule1, left value rule2] compared to [right value rule1, right value rule2]
The spaceship operator (<=>) will compare the corresponding element one at a time "rule1 vs rule1" then "rule2 vs rule2" as needed.

Group Array By Range Value

I have this array [1,1,2,2,2,3,4,4,5,6,6,6,7], may I group the array according to the range value, so get the final result:
'1-3' = [1,1,2,2,2,3]; // Count is 6
'4-5' = [4,4,5]; // Count is 3
'6-7' = [6,6,6,7]; // Count is 4
What you need I believe is:
function array_get_range($array, $min, $max) {
return array_filter($array, function($element) use ($min, $max) {
return $element >= $min && $element <= $max;
});
}
$array = [1,1,2,2,2,3,4,4,5,6,6,6,7];
$range13 = array_get_range($array, 1, 3); // [1, 1, 2, 2, 2, 3]
$range45 = array_get_range($array, 4, 5); // [4, 4, 5]
$range67 = array_get_range($array, 6, 7); // [6, 6, 6, 7]
Create a new array with your ranges, then iterate through the values and through the ranges inside. If the current value is inside the range, add the record to the current range:
<?php
$numbers = [1,1,2,2,2,3,4,4,5,6,6,6,7];
$counts = [];
$counts[] = ["values"=> [1, 3], "records" => []]; // first value in "values" is min, second is max
$counts[] = ["values"=> [4, 5], "records" => []];
$counts[] = ["values"=> [6, 7], "records" => []];
foreach ($numbers as $number) {
foreach ($counts as $key => &$value) {
if ($number >= $value["values"][0] && $number <= $value["values"][1]) { // if between the range, add it to the records
$value["records"][] = $number;
}
}
}
echo "<pre>";
foreach ($counts as $count) {
echo $count["values"][0]." - ".$count["values"][1]." = ".count($count["records"])." elements<br>";
}
Demo
I think array_intersect() and range() with sizeof()/count() does a cleaner job for this task. It eliminates the double-conditional.
Code: (Demo)
function count_range($array, $min, $max) {
return sizeof(array_intersect($array, range($min, $max)));
}
$array = [1, 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 7];
echo count_range($array, 1, 3); // 6 from [1, 1, 2, 2, 2, 3]
echo count_range($array, 4, 4); // 2 from [4, 4]
echo count_range($array, 2, 7); // 11 from [2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 7]
range() creates a whitelist array of one or more consecutive integers.
array_intersect() compares the input array and the whitelist array all at once.
sizeof() is just an alias of count() to determine how many elements were retained.

Merging of array items

I have already asked this question once for a solution in Python:
python intersect of dict items
but I am now looking for the equivalent solution in PHP. Specifically I am using CakePHP 2.0 on the ConsoleShell.
I have an undetermined number of nests in an array and I want to loop over them like this:
$array = array(1 => array(1, 2, 3, 4), 2 => array(7, 8), n => array(n1, n2, n3))
foreach($array[1] as $k1 => $v1) {
foreach($array[2] as $k2 => $v2) {
foreach($array[n] as $kn => $vn) {
// do something with this combination
}
}
}
Bear in mind that n can be any number (the total number of nests), so I need code that allows for a dynamic number of nests.
Any ideas please?
Thanks
EDIT:
Just to clarify what I am after, if
$array = array(array(0, 1, 2, 3), array(0, 6, 7), array(0, 9, 10));
I want to end up with:
$array2 = array(
array(0, 0, 0),
array(0, 0, 9),
array(0, 0, 10),
array(0, 6, 0),
array(0, 6, 9),
...
array(3, 6, 10),
array(3, 7, 0),
array(3, 7, 9),
array(3, 7, 10)
);
however if $array has 4 array elements, then $array2 should have 4 elements on each line etc.
function dosomething($a) {
if (is_array($a))
foreach ($a as $aa)
dosomething($aa)
else {
//do something
}
}
Edit:
After the OQ was updated it became clear, that not the depth is variable, but the element count. So we do not need recursion, but nested foreaches
This gives the output as requested in the OQ
<?php
$array = array(array(0, 1, 2, 3), array(0, 6, 7), array(0, 9, 10));
$result=array(array());
foreach ($array as $a) {
$oldresult=$result;
$result=array();
foreach ($oldresult as $or) {
foreach($a as $aa) {
$nr=$or;
$nr[]=$aa;
$result[]=$nr;
}
}
}
print_r($result);
?>
In short: We start with a result array, that has one element: an empty array. Now we cycle through the first level of the input array, in every step we replace all elements of the result array with a series of elements consiting of the original element with each of the members of our current array attached.
The first iteration replaces
array() with array(0), array(1), array(2), array(3)
The second iteration replaces
array(0) with array(0,0), array(0,6), array(0,7)
array(1) with array(1,0), array(1,6), array(1,7)
...
The third iteration replaces
array(0,0) with array(0,0,0), array(0,0,9), array(0,0,10)
array(0,1) with array(0,1,0), array(0,1,9), array(0,1,10)
...
array(1,0) with array(1,0,0), array(1,0,9), array(1,0,10)
...

Categories