I have a multidimentional array like this:
$my_array = array(
array($user_id, $id, $type, $log, $url, $timestamp),
array($user_id, $id, $type, $log, $url, $timestamp),
array($user_id, $id, $type, $log, $url, $timestamp),
// and so on...
);
$my_array has a random amount of arrays inside. I want to limit the amount of arrays to 5 inside $my_array. How can I achieve this? So, if there are 5 arrays inside, and one more is added, then remove the last array...
Just use a function to add arrays to it, then do your checks. E.g
function addToArray($arr, $newValue, $limit=5) {
if (count($arr) >= $limit) {
array_shift($arr);
}
$arr[] = $newValue;
return $arr;
}
The function array_shift removes the first element and returns the shortened array.
If it is possible for things to be added to the array outside of this function, you can generalize:
function addToArray($arr, $newValue, $limit=5) {
while (count($arr) >= $limit) {
array_shift($arr);
}
$arr[] = $newValue;
return $arr;
}
EDIT: Added improvements suggested by Jonathan Kuhn.
Add the new value and then call array_slice.
If you want to add to the end of the array:
//array with more than 5
$array = range(1, 8); // [1, 2, 3, 4, 5, 6, 7, 8]
//add the element
$array[] = 9;
//get the last 5
$array = array_slice($array, -5);
//output: [5, 6, 7, 8, 9]
http://codepad.viper-7.com/DL91ZK
If you want to add to the beginning of the array
//array with more than 5
$array = range(1, 8); // [1, 2, 3, 4, 5, 6, 7, 8]
//add to the array
array_unshift($array, 0);
//get the first 5
$array = array_slice($array, 0, 5);
//output: [0, 1, 2, 3, 4]
http://codepad.viper-7.com/RGfohJ
Related
I have an array of elements like this:
$data = array(1, 2, 3, 4);
How can I reorder for example, starting from second element to get 2, 3, 4, 1; or starting from third element to get 3, 4, 1, 2?
One solution is to use array_slice function to separate the two portions and combine them with array_merge:
$data = [1, 2, 3, 4];
$pos = 2;
$ordered = array_merge(
array_slice($data, $pos),
array_slice($data, 0, $pos)
);
// [3, 4, 1, 2]
You can use array_splice
$data = array(1,2,3,4);
$out = array_splice($data, 1, 3);
array_splice($data, 0, 0, $out);
print_r($data);
You could just array_shift() and then push the shifted value back on to the end of the Array:
$data = array(1,2,3,4);
$data[] = array_shift($data);
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);
I have a array like this:
$row_arr_1=array(7,9,5,10);
now I want to get the result array like this:
$row_arr_2=array(3,2,4,1);
Explanation:
As 10 is the largest value in row_arr_1, then it will be replaced with value 1.
Similarly, as 9 is the 2nd highest value of row_arr_1, then it will be replaced by 2 and so on.
I tried to sort the values of row_arr_1 but the position is changed.
How
can i get my desired result?
It can be done using rsort() and array_search()
$row_arr_1=array(7,9,5,10);
$row_copy = $row_arr_1;
$row_arr_2 = array();
rsort($row_copy);
foreach($row_arr_1 as $val) {
$row_arr_2[] = array_search($val, $row_copy) + 1;
}
print_r($row_arr_2);
https://eval.in/990078
You can use arsort() to sort the array while preserving keys, and use those keys for your array via array_keys():
$row_arr_1 = array(7,9,5,10);
$row_arr_1_backup = $row_arr_1;
arsort($row_arr_1_backup);
$row_arr_2 = array_keys($row_arr_1_backup);
asort($row_arr_2);
$row_arr_2 = array_keys($row_arr_2);
array_walk($row_arr_2, function(&$item, &$key) {
$item = $item + 1;
});
You have to duplicate the original array, since arsort will sort the actual array it points to, rather than returning a new array.
$row_arr_1_old = array(7, 9, 5, 10);
$row_arr_1 = array(7, 9, 5, 10);
rsort($row_arr_1);
$test = [];
foreach ($row_arr_1_old as $key => $value) {
$test[] = array_search($value, $row_arr_1);
}
print_r($test);
For best efficiency try to reduce total function calls; this especially means minimizing / eliminating iterated function calls.
This is my slightly more efficient version of ahsan's answer.
Code: (Demo)
$copy = $arr = [7, 9, 5, 10];
rsort($arr); // generates: [10, 9, 7, 5]
$flipped = array_flip($arr); // generates: [10 => 0, 9 => 1, 7 => 2, 5 => 3]
foreach($copy as $v) {
$result[] = ++$flipped[$v]; // adds one to each accessed value from $flipped
}
var_export($result);
Output:
array (
0 => 3,
1 => 2,
2 => 4,
3 => 1,
)
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.
I want to merge every element of two arrays, BUT if a value is in both arrays, then only add the values from the array which has the biggest amount of that element. The result array does not need to be sorted in any special way, but I did it here for readability.
Sample input:
$array1 = [1, 4, 7, 3, 3, 3];
$array2 = [4, 0, 3, 4, 9, 9];
Desired result:
[0, 1, 3, 3, 3, 4, 4, 7, 9, 9]
//a2 a1 a1 a1 a1 a2 a2 a1 a2 a2
Note, this will be used on big arrays, with unknown integer values. Is there a good way to do this that doesn't require too much time/processing power?
Try this:
<?php
$array1 = [1, 4, 7, 3, 3, 3];
$array2 = [4, 0, 3, 4, 9, 9];
function min_merge($arr1, $arr2) {
$arr1 = array_count_values($arr1);
$arr2 = array_count_values($arr2);
foreach ($arr2 as $index => $arr)
if (!isset($arr1[$index]) || $arr > $arr1[$index])
$arr1[$index] = $arr;
foreach ($arr1 as $index => $arr)
for ($i = 0; $i < $arr; $i++)
$final[] = $index;
return $final;
}
print_r(min_merge($array1, $array2));
Output:
Array (
[0] => 1
[1] => 4
[2] => 4
[3] => 7
[4] => 3
[5] => 3
[6] => 3
[7] => 0
[8] => 9
[9] => 9
)
Unsorted, but it contains all the numbers from [0, 1, 3, 3, 3, 4, 4, 7, 9, 9].
$count[0] = array_count_values($arr1);
$count[1] = array_count_values($arr2);
$out = array();
array_map(function($e) use(&$out, $count){
$n1 = (isset($count[0][$e])) ? $count[0][$e] : 0;
$n2 = (isset($count[1][$e])) ? $count[1][$e] : 0;
$next = ($n2 > $n1) ? array_fill(0, $n2, $e) : array_fill(0, $n1, $e);
$out = array_merge($out, $next);
}, array_keys($count[0] + $count[1]));
print_r($out);
My modernized rewrite of #DaveChen's answer using PSR-12 coding standards and eliminating single-use declarations. This approach uses one loop to determine the greater count for numbers shared by both value-count arrays, then a second loop to populate the result array. (Demo)
$counts1 = array_count_values($array1);
foreach (array_count_values($array2) as $number => $count) {
if ($count > ($counts1[$number] ?? 0)) {
$counts1[$number] = $count;
}
}
$result = [];
foreach ($counts1 as $number => $count) {
array_push($result, ...array_fill(0, $count, $number));
}
var_export($result);
My modernized rewrite of #Expedito's answer which does not abuse the array_map() (when array_map()'s return value is not used, use array_walk() for functional style programming), uses a foreach() loop to eliminate variable scope issues, and generally implements D.R.Y. techniques. (Demo)
$counts1 = array_count_values($array1);
$counts2 = array_count_values($array2);
$result = [];
foreach ($counts1 + $counts2 as $num => $cnt) {
array_push(
$result,
...array_fill(
0,
max($counts1[$num] ?? 0, $counts2[$num] ?? 0),
$num
)
);
}
var_export($result);
And I wanted to add a new approach of my own, despite the fact that it may or may not perform better than the other two snippets. The script makes one pass over the first value count arrays to populate a temporary array which demands which numbers from the first array should be represented in the result array. Then it isolates value intersections from the first array, value differences from the second array, then merges them. (Demo)
$counts1 = array_count_values($array1);
$counts2 = array_count_values($array2);
$keepFrom1 = array_keys(
array_filter(
$counts1,
fn($count, $number) => ($counts2[$number] ?? 0) <= $count,
ARRAY_FILTER_USE_BOTH
)
);
var_export(
array_merge(
array_intersect($array1, $keepFrom1),
array_diff($array2, $keepFrom1)
)
);
probably not the most optimized but
<?php
$one=[1, 4, 7, 3, 3, 3];
$two=[4, 0, 3, 4, 9, 9];
sort($one);
sort($two);
foreach($one as $el)
{
$combined[]=$el;
if (array_search($el,$two))
{
unset($two[array_search($el,$two)]);
}
}
foreach($two as $el)
{
$combined[]=$el;
}
sort($combined);
print_r($combined);
?>