Related
How can I subtract the value of an array if that value is greater than specific data?
For example:
I have an array of menu's position [0,3,10,5,6,9,2,7,1,4,8,11] I want to subtract all values that are greater than selectedDeletedNumbers and stay in their position.
Example: If I delete 3 and 5. I am using checkbox to delete
And the output should be like this.
[0,8,4,7,2,5,1,3,6,9]
Greater than 3 is subtract by 1, and greater than 5 is subtract by 2 since I selected 2 numbers.
HTML
#foreach ($columns as $key => $column)
<div class="checkbox checkbox-danger col-xs-6 el{{ $column->Field }}">
<input type="checkbox" name="CheckboxDelete[]" id="check{{ $column->Field }}" data-column="{{ $key }}" value="{{ $column->Field }}">
<label for="check{{ $column->Field }}"><b style="color: grey">{{ strtoupper($column->Field) }}</b></label>
</div>
#endforeach
Here is my code, but it's only when deleted 1, and not in a position as well.
$searchArr = array_search( $selectedDeletedNumbers, $items);
unset($items[$searchArr]);
$numbers = [];
foreach ($items as $item) {
if ($item > $col[1])
$numbers[] = $item - 1;
}
Thanks in advance.
For clarity and brevity, I'll refer to your input data as:
$array = [0, 3, 10, 5, 6, 9, 2, 7, 1, 4, 8, 11];
$deletes = [3, 5];
There is no sorting or preparation required for either of my snippets.
Output for both of the following are:
array (
0 => 0,
1 => 8,
2 => 4,
3 => 7,
4 => 2,
5 => 5,
6 => 1,
7 => 3,
8 => 6,
9 => 9,
)
Mostly function based approach: (Demo)
foreach (array_diff($array, $deletes) as $value) {
$result[] = array_reduce(
$deletes,
function ($carry, $item) use ($value) {
return $carry - ($value > $item);
},
$value
);
}
var_export($result);
*note: ($value > $item) will evaluated as true or false, when used in arithmetic, true = 1 and false = 0.
Language construct based approach: (Demo)
foreach ($array as $value) {
foreach ($deletes as $delete) {
if ($value == $delete) {
continue 2; // goto next value in outer loop without pushing
}
if ($value > $delete) {
--$value; // decrement value
}
}
$result[] = $value; // push adjusted value into result array
}
var_export($result);
The advantage in this snippet is that there are zero function calls and minimal variables declared.
To delete numbers from array and to subtract a count from the current number in the original array with the number of numbers smaller than it in selectedDeletedNumbers, you can:
Sort the selectedDeletedNumbers array.
Iterate over the original array and use binary search to get the count of numbers smaller than the current number in the original array and subtract it later.
If current number is present in selectedDeletedNumbers, then unset them.
Snippet:
<?php
$arr = [0,3,10,5,6,9,2,7,1,4,8,11];
$selectedDeletedNumbers = [3,5];
sort($selectedDeletedNumbers);
foreach($arr as $index => $val){
$low = 0;$high = count($selectedDeletedNumbers) - 1;
$equal_found = false;
while($low <= $high){
$mid = intval(($low + $high) / 2);
if($selectedDeletedNumbers[$mid] > $val){
$high = $mid - 1;
}else if($selectedDeletedNumbers[$mid] < $val){
$low = $mid + 1;
}else{
$equal_found = true;
unset($arr[$index]);
break;
}
}
if(!$equal_found){
$arr[$index] -= $low;
}
}
print_r($arr);
Demo: http://sandbox.onlinephpfunctions.com/code/ca881fce6a27c216f24a1701190940a87132ab1c
This way, the time complexity will be max(O(m log(m)),O(n log(m))) where n is size of original array and m is the size of selectedDeletedNumbers and space complexity is O(1).
If you want to re-index the numbers sequentially, do an $arr = array_values($arr) in the end.
One more solution is to optimize the checking of what to delete. This code makes sure the delete list is a 0 based array, so in the example it ensures it's
[ 0 => 3, 1 => 5 ]
Then it sorts it descending, but keeps the key, so
[ 1 => 5, 0 => 3 ]
Then when checking the numbers, if the number is greater than 5, it subtracts the key+1, so 1+1 = 2 (sorry for the basic maths). It can then stop and doesn't have to check any more.
$menu = [0,3,10,5,6,9,2,7,1,4,8,11];
$selectedDeletedNumbers = [3,5];
// In case array is not just 0 based index, can remove if it will be
$selectedDeletedNumbers = array_values($selectedDeletedNumbers);
// Sort so highest first, keep key (this is the offset)
arsort($selectedDeletedNumbers);
foreach ( $menu as $key => $menuItem ) {
foreach ( $selectedDeletedNumbers as $deleteIndex => $delete ) {
// Matching, just remove and carry on
if ( $menuItem == $delete ) {
unset($menu[$key]);
break;
}
// Greater than item, so deduct index and move on
if ( $menuItem > $delete ) {
$menu[$key] -= ($deleteIndex+1);
break;
}
}
}
print_r($menu);
If your selected array might come in any order, you can replace the
$selectedDeletedNumbers = array_values($selectedDeletedNumbers);
line with...
sort($selectedDeletedNumbers);
for ($i = 0; $i < count($menuPositions); $i++) {
for ($j = 0; $j < count($selectedDeletedNumbers); $j++) {
if ($menuPositions[$i] == $selectedDeletedNumbers[$j]) {
unset($menuPositions[$i]); // remove the match value from array
$menuPositions = array_values($menuPositions); // reorganize array keeping only the values are not null
$i--; //include the new value of $menuPositions[$i] on interation
break;
}
if ($menuPositions[$i] > $selectedDeletedNumbers[$j] ) {
$menuPositions[$i]--;
}
}
}
For example, input array is [9,1,9,1,3,9,1,2,9] output array will be [9,9,9,9,1,1,1,2,3].
Here's what I've tried below but not giving me expected result:
$array = [9,1,9,1,3,9,1,2,9];
$values = array_count_values($array);
arsort($values);
$popular = array_keys($values);
print_r(array_values($popular));
foreach ($values as $key => $val) {
echo $key.", ";
}
Output:
Array
(
[0] => 9
[1] => 1
[2] => 3
[3] => 2
)
9, 1, 3, 2,
If we loop the array_count_values then we can make sure they come in the correct order.
When there is two that is the same count I find all the same with array_intersect then foreach them and add in the correct order.
$array = [9,1,9,1,3,9,1,2,9];
$values = array_count_values($array);
arsort($values);
//var_dump($values);
$result =[];
$same = [];
foreach($values as $key => $val){
if(!in_array($key, array_keys($same))){
if(next($values) != $val){
$result = array_merge($result, array_fill(0, $val, $key));
}else{
$same = array_intersect($values, [$val]);
ksort($same);
foreach($same as $skey => $val){
$result = array_merge($result, array_fill(0, $val, $skey));
}
//var_dump($same);
}
}
}
var_dump($result);
https://3v4l.org/sk44Q
Try usort combined with array_count (php >= 7.0):
$array = [9,1,9,1,3,9,1,2,9];
$arrayCounts = array_count_values($array);
usort($array, function ($a, $b) use ($arrayCounts) {
$countA = $arrayCounts[$a] ?? 0;
$countB = $arrayCounts[$b] ?? 0;
if ($countA == $countB) {
return $a == $b ? 0 : ($a < $b ? -1 : 1);
}
return ($countA > $countB) ? -1 : 1;
});
You could use this sequence:
$arrayCounts = array_count_values($array);
usort($array, function ($a, $b) use ($arrayCounts) {
return $arrayCounts[$b] - $arrayCounts[$a] ?: $a - $b;
});
Now $array is sorted as requested.
The callback function that is passed as argument to usort should return a negative number when the two elements $a and $b should stay in that order (from left to right), or a positive number when they should be reversed. 0 when it does not matter.
The numeric expression that is returned in this particular callback function subtracts the frequencies of $a and $b. If $b occurs more, then that subtraction is positive, and that is returned. Similarly if the subtraction is negative, then that negative value is returned. Now when the frequencies are equal, the ?: operator kicks in and the expression after it is evaluated. That other subtraction also results in a positive or negative value, based on the original value itself. So $a - $b will be negative when $a < $b, which means the order can remain as it is (knowing that we already derived that their frequencies were equal).
I want to find minimum value from an array and subtract that value from all the elements until all the elements becomes 0. The problem is that if the array contains one of the element as 0 then it doesn't reflect anything. Thanks in advance.
<?php
$handle = fopen ("php://stdin","r");
fscanf($handle,"%d",$n);
$arr_temp = fgets($handle);
$arr = explode(" ",$arr_temp);
array_walk($arr,'intval');
for($j=0;$j<10;$j++)
{
$min = min($arr);
for($i=0;$i<count($arr);$i++)
{
if($arr[$i]>=$min)
$arr[$i]-=$min;
echo $arr[$i]." ";
}
echo "\n";
}
?>
Using array_filter(), plus a function you can get the minimum positive non-zero integer even if an array contains elements whose value is zero, as follows:
<?php
$arr = array(0, 1, 2, 3, 4, 0, 5, 6, 4, 3, 2, 1,0);
function getMin( $a ) {
$arr_filtered = array_values(array_filter( $a ));
return min($arr_filtered);
}
$min = getMin( $arr );
$count = count($arr);
while( count( array_unique($arr) ) > 1 ) {
for( $i = 0; $i < $count; $i++)
{
if( $arr[$i] >= $min ){
$arr[$i] -= $min;
echo $arr[$i]." ";
}
}
echo "\n";
}
See demo
Note, the code re-indexes the filtered array in getMin() by using array_values().
As long as the minimum value is one the above script works well. However, if the minimum value were another number, then the code needs to be adjusted. The following script handles a multi-dimensional array composed of four arrays, each with a different minimum value, including one with negative values:
<?php
error_reporting(E_ALL);
$a = [ [0,1, 2, 3, 4, 0, 5, 6, 4, 3, 2, 1,0],
[0, 2, 3, 4, 0, 5, 6, 4, 3, 2, 0],
[0, 3, 4, 0, 5, 6, 7,8,4, 3, 0],
[-1,0,1,2,3,4,2,1,0,-1]
];
function getMin( $a ) {
return min($a);
}
foreach ($a as $arr) {
while( ( $arr != null ) ) {
$arr = array_values(array_filter($arr));
if ($arr == null) {
break;
}
$min = getMin( $arr );
foreach ($arr as &$e) {
$e -= $min;
}
unset($e);
echo join(" ",$arr),"\n";
}
echo "\n";
}
see demo
Note, the second script explicitly filters out the zero values in each array whereas the first script effectively does so. The primary difference between the two scripts is that getMin() needs to be in the while loop so that the subtraction correctly occurs when the minimum number is greater than one or is a negative number.
The script also simplifies the code in several ways. Much more simple condition for the while loop -- works as long as array is not null. The code no longer needs getCount() since I changed the subtraction loop to use a foreach with a reference variable which is subsequently unset -- important to do to avoid problems. This foreach loop also does not require the if conditional of the first script.
It is because you taking each and every time $min = min($arr); value and it became 0 thats why your code is not working.
try below code
$min = min($arr);
for($j=0;$j<=100;$j++)
{
if (count(array_unique($arr)) === 1 && end($arr) === 0) {
break;
}
for($i=0;$i<count($arr);$i++)
{
if($arr[$i] >= $min){
$arr[$i]-=$min;
echo $arr[$i]." ";
}
}
echo "<br>";
}
I do not know much about php but in the first for loop you should check the elements of the array if they are zero or not using if statements e.g if(arr[j]!=0)
for($j=0;$j<10;$j++)
{
if($arr[$j]!=$0)
$min = min($arr);
for($i=0;$i<count($arr);$i++)
{
if($arr[$i]>=$min)
$arr[$i]-=$min;
echo $arr[$i]." ";
}
echo "\n";
}
I have an array. I'd like to get the three highest values of the array, but also remember which part of the array it was in.
For example, if my array is [12,3,7,19,24], my result should be values 24,19,12, at locations 4, 0, 3.
How do I do that? The first part is easy. Getting the locations is difficult.
Secondly, I'd like to also use the top three OR top number after three, if some are tied. So, for example, if I have [18,18,17,17,4], I'd like to display 18, 18, 17, and 17, at location 0,1,2,3.
Does that make sense? Is there an easy way to do that?
Wouldn't you be there using asort()?
For example:
<?php
$list = [4,18,18,17,17];
// Sort maintaining indexes.
asort($list);
// Slice the first 3 elements from the array.
$top3 = array_slice($list, -3, null, true);
// Results in: [ 1 => 18, 2 => 18, 3 => 17 ]
Or you can use arsort
function getMyTop($list, $offset, $top) {
arsort($list);
return array_slice($list, $offset, $top, true);
}
$myTop = getMyTop($list, 0, 3);
$myNextTop = getMyTop($list, 3, 4);
This is what you need!
<?php
$array = array(12,3,7,19,24);
$array_processed = array();
$highest_index = 0;
while($highest_index < 3)
{
$max = max($array);
$index = array_search($max,$array);
$array_processed[$index] = $max;
unset($array[$index]);
$highest_index++;
}
print_r($array_processed);
?>
You will get Index as well as the value! You just have to define how many top values you want! Let me know if it's what you want!
function top_three_positions($array){
// Sort the array from max to min
arsort($array);
// Unset everything in sorted array after the first three elements
$count = 0;
foreach($array as $key => $ar){
if($count > 2){
unset($array[$key]);
}
$count++;
}
// Return array with top 3 values with their indexes preserved.
return $array;
}
You can use a loop to determine how many elements your top-three-with-ties will have, after applying arsort:
function getTop($arr, $num = 3) {
arsort($arr);
foreach(array_values($arr) as $i => $v) {
if ($i >= $num && $v !== $prev) return array_slice($arr, 0, $i, true);
$prev = $v;
}
return $arr;
}
// Sample input
$arr = [4,18,17,6,17,18,9];
$top = getTop($arr, 3);
print_r($top); // [5 => 18, 1 => 18, 4 => 17, 2 => 17]
try this:
public function getTopSortedThree(array $data, $n = 3, $asc = true)
{
if ($asc) {
uasort($data, function ($a, $b) { return $a>$b;});
} else {
uasort($data, function ($a, $b) { return $a<$b;});
}
$count = 0;
$result = [];
foreach ($data as $key => $value) {
$result[] = $data[$key];
$count++;
if ($count >= $n){
break;
}
}
return $result;
}
Send false for desc order and nothing for asc order
Send $n with number of top values you want.
This functionality doesn't losing keys.
This task merely calls for a descending sort, retention of the top three values, and in the case of values after the third-positioned value being equal to the third value, retain these as well.
After calling rsort(), call a for() loop starting from the fourth element ([3]). If the current value is not equal to the value in the third position, stop iterating, and isolate the elements from the front of the array to the previous iteration's index. Done.
p.s. If the input array has 3 or fewer elements, the for() loop is never entered and the whole (short) array avoids truncation after being sorted.
Code: (Demo)
$array = [18, 17, 4, 18, 17, 16, 17];
rsort($array);
for ($i = 3, $count = count($array); $i < $count; ++$i) {
if ($array[2] != $array[$i]) {
$array = array_slice($array, 0, $i);
break;
}
}
var_export($array);
Because the loop purely finds the appropriate finishing point of the array ($i), this could also be compacted to: (Demo)
rsort($array);
for ($i = 3, $count = count($array); $i < $count && $array[2] === $array[$i]; ++$i);
var_export(array_slice($array, 0, $i));
Or slightly reduced further to: (Demo)
rsort($array);
for ($i = 3; isset($array[2], $array[$i]) && $array[2] === $array[$i]; ++$i);
var_export(array_slice($array, 0, $i));
Output:
array (
0 => 18,
1 => 18,
2 => 17,
3 => 17,
4 => 17,
)
How can I generate following random array:
array(1, 0 , 0, 1, 1, 1, 1, 0, 1, 0, 0)
with length = n?
Of course, always the for solution is out there. But is there any One-line simple solution on this, like any combination of array_fill and mt_rand(0, 1)?
You can use combination of array_map and range (or array_fill if you need) to generate random values.
$length = 10;
$randBits = array_map(
function () {
return mt_rand(0, 1);
},
range(0, $length - 1)
);
Working example
Use range with mt_rand
$random_bit_stream = array_map(function() {
return mt_rand(0,1);
}, range(1,6));
or
$random_bit_stream = array_map(function() {
return rand(0,1);
}, range(1,6));
print_r($random_bit_stream);
Output:
Array ( [0] => 0 [1] => 1 [2] => 1 [3] => 1 [4] => 0 [5] => 0 )
try this,
function randome_array($n)
{
$array=array();
$x = 1;
while($x <= $n) {
$temp = mt_rand(0,1);
array_push($array,$temp);
$x++;
}
return $array;
}
print_r(randome_array(5));
https://3v4l.org/ZSrMX
i hope it will be helpful.
Well, as you mentioned, you could one-line the for solution.
for ($i = 0; $i < count($arr); $i++) $arr[$i] = rand(0, 1);
aside that, since you mentioned array_fill, you could simply use it with the random function as well
$arr = array_fill (0, count($arr), rand(0, 1));
You can try with range()
range — Create an array containing a range of elements
for more info check http://php.net/manual/en/function.range.php