PHP reordering array - php

I've got an array per default:
array( 1=>1,2 =>2, 3=>3, 4=>4, 5=>5, 6=>6, 7=>7, 8=>8, 9=>9 )
Now an operation is possible to change the numbers for example into:
array( 1=>1, 2=>1, 3=>3, 4=>1, 5=>1, 6=>6, 7=>7, 8=>8, 9=>9 )
--> changed the value of key 1, 2, 4 and 5
After this I need the following result
array( 1=>1, 2=1, 3=>2, 4=>1, 5=>1, 6=>3, 7=>4, 8=>5, 9=>6 )
--> changed the value of key 3, 6, 7, 8, 9 in the right order that no number is missing like the operation has done above.
Its a grid 3x3. Position 1 is 1, Position 2 is 2 and so on. Now a database could set that Position 1, 2, 4, 5 are the same and threated as 1. So the database sends: 1, 1, 3, 1, 1, 6, 7, 8, 9. Now the field from place 3 is 3, but should be the field from 2. Also the field from 6 must now be field 3 and so on.
Note: The operation is able to change every value in the array. for example the value of the
keys 4, 5, 7, 8
How can I do this?

Create a variable, in which you will store the max number. If you then iterate, check if the number from the array is lower then max, and if it is, then you do nothing, and if it is larger than max, so you put it in the third array and increase max.
$max = 0; // maximum value
$array3 = array(); // output array
foreach($array2 as $key=>$element){ // iterate for all elements
if($array2[$key] > $max){
$max++;
$array3[$key] = $max;
}
else
$array3[$key]=1; // *
} // end foreach
In the line marked with // * it puts 1 everytime. You may need to search if the value was once before, because it does not need to be always 1. You may use for example something like array_search.

Related

Find the smallest positive integer that does not occur in an array

I am trying out the following codility.com exercise to improve my skills online, I was presented with the following problem.
This is a demo task.
Write a function:
class Solution { public int solution(int[] A); }
that, given an array A of N integers, returns the smallest positive
integer (greater than 0) that does not occur in A.
For example,
given A = [1, 3, 6, 4, 1, 2], the function should return 5.
Given A = [1, 2, 3], the function should return 4.
Given A = [-1, -3], the function should return 1.
Write an efficient algorithm for the following assumptions:
• N is an
integer within the range [1..100,000);
• each element of array A is an
integer within the range (-1,000,000..1,000,000).
Copyright 2009– by Codility Limited
rendered description
I solved it using the following solution:
<?php
class Solution {
public function($A) {
$posInts = [1, 2, 3, 4, 5, 6, 7, 8, 9];
$diffs = array_diff($postInts, $A);
$smallestPosInt = min($diffs);
return $smallestPosInt;
}
}
However upon submitting I got the following score:
Now I am very unsure of what I did wrong here or how I can rewrite the code with a better algorithm.
Check out this answer using Javascript in a way that works with the best possible performance -If I am not mistaken- O(N).
function solution(A) {
const set = new Set(A)
let i = 1
while (set.has(i)) {
i++
}
return i
}
I would just loop over (increment) any possible integers:
function solution($A) {
$result = 1;
$maxNumber = max($A);
for (; $result <= $maxNumber; $result++) {
if (!in_array($result, $A)) {
break;
}
}
return $result;
}
var_dump(solution([1, 3, 6, 4, 1, 2])); // int(5)
var_dump(solution([1, 2, 3])); // int(4)
var_dump(solution([-1, -3])); // int(1)
// As a bonus, this also works for larger numbers:
var_dump(solution([1, 3, 6, 4, 1, 2, 7, 8, 9, 10, 11, 12, 13, 5, 15])); // int(14)
Edit regarding performance:
As pointed out in the comments (and you already said yourself), this is not a very efficient solution.
While I do not have enough time on my hands currently to do real performance testing, I think this should be close to an O(n) solution: (keeping in mind that I am not sure how arrays are implemented on the C-side of PHP)
function solution($A) {
$result = 1;
$maxNumber = max($A);
$values = array_flip($A);
for (; $result <= $maxNumber; $result++) {
if (!isset($values[$result])) {
break;
}
}
return $result;
}
// Not posting the output again because it is naturally the same ;)
The "trick" here is to flip the array first so that the values become the indexes. Since a) we do not care about the original indexes and b) we do not care if duplicated values overwrite each other, we can safely do that.
Using isset() instead of in_array() should be a lot quicker since it basically just checks if a variable (in this case stored at a specific index of the array) exists and PHP does therefore not have to iterate through the array in order to check whether or not each number we loop over exists within it.
P.S.: After thinking twice I think this may still be closer to O(n*2) because max() probably loops to find the highest value. You could also remove that line and just check against the highest number there is in PHP as an emergency exit, like so: for (; $result <= PHP_INT_MAX; $result++) { ... } as a further optimization. Or maybe just hard-code the highest allowed number as specified in the task.
If we're allowed to modify the input, perform this in place, otherwise create a new array of size n + 1:
For each element encountered in the original array, if it is greater than n + 1 or smaller than 1, assign 0 at the element's index (index - 1 if performing in place); otherwise assign 1 at the index of the array the value is and assign 0 at its own index if it is different. After that run a second traversal and report the first index (index + 1 if performing in place) greater than zero with value 0, or n + 1.
[1, 3, 6, 4, 1, 2]
=>
[1, 1, 1, 1, 0, 1]
report 5

Iterate through 2d array of booleans and leave only the largest contiguous "2D blob of ones"

Ok, so the question is kind of awkwardly phrased, but I hope this will clear things up.
I have this sample 2d array.
$array = array(
array(1, 0, 0, 0, 1, 0, 0, 1),
array(0, 0, 1, 1, 1, 1, 0, 1),
array(0, 1, 1, 0, 1, 0, 0, 0),
array(0, 1, 1, 0, 0, 0, 1, 0),
array(1, 0, 0, 0, 1, 1, 1, 1),
array(0, 1, 1, 0, 1, 0, 1, 0),
array(0, 0, 0, 0, 0, 0, 0, 1)
);
When iterated by rows (and terminating each row with \n), and for every row then iterated by column, it will echo something like this: (░░ = 0, ▓▓ = 1)
▓▓░░░░░░▓▓░░░░▓▓
░░░░▓▓▓▓▓▓▓▓░░▓▓
░░▓▓▓▓░░▓▓░░░░░░
░░▓▓▓▓░░░░░░▓▓░░
▓▓░░░░░░▓▓▓▓▓▓▓▓
░░▓▓▓▓░░▓▓░░▓▓░░
░░░░░░░░░░░░░░▓▓
But what I'd like to do is to "analyse" the array and only leave 1 contiguous shape (the one with the most "cells"), in this example, the result would be:
░░░░░░░░▓▓░░░░░░
░░░░▓▓▓▓▓▓▓▓░░░░
░░▓▓▓▓░░▓▓░░░░░░
░░▓▓▓▓░░░░░░░░░░
▓▓░░░░░░░░░░░░░░
░░▓▓▓▓░░░░░░░░░░
░░░░░░░░░░░░░░░░
My initial approach was to:
Assign each ▓▓ cell a unique number (be it completely random, or the current iteration number):
01 02 03
04050607 08
0910 11
1213 14
15 16171819
2021 22 23
24
Iterate through the array many, MANY times: every iteration, each ▓▓ cell assumes the largest unique number among his neighbours. The loop would go on indefinitely until there's no change detected between the current state and the previous state. After the last iteration, the result would be this:
01 21 08
21212121 08
2121 21
2121 24
21 24242424
2121 24 24
24
Now it all comes down to counting the value that occurs the most. Then, iterating once again, to turn all the cells whose value is not the most popular one, to 0, giving me the desired result.
However, I feel it's quite a roundabout and computationally heavy approach for such a simple task and there has to be a better way. Any ideas would be greatly appreciated, cheers!
BONUS POINTS: Divide all the blobs into an array of 2D arrays, ordered by number of cells, so we can do something with the smallest blob, too
Always fun, these problems. And done before, so I'll dump my code here, maybe you can use some of it. This basically follows every shape by looking at a cell and its surrounding 8 cells, and if they connect go to the connecting cell, look again and so on...
<?php
$shape_nr=1;
$ln_max=count($array);
$cl_max=count($array[0]);
$done=[];
//LOOP ALL CELLS, GIVE 1's unique number
for($ln=0;$ln<$ln_max;++$ln){
for($cl=0;$cl<$cl_max;++$cl){
if($array[$ln][$cl]===0)continue;
$array[$ln][$cl] = ++$shape_nr;
}}
//DETECT SHAPES
for($ln=0;$ln<$ln_max;++$ln){
for($cl=0;$cl<$cl_max;++$cl){
if($array[$ln][$cl]===0)continue;
$shape_nr=$array[$ln][$cl];
if(in_array($shape_nr,$done))continue;
look_around($ln,$cl,$ln_max,$cl_max,$shape_nr,$array);
//SET SHAPE_NR to DONE, no need to look at that number again
$done[]=$shape_nr;
}}
//LOOP THE ARRAY and COUNT SHAPENUMBERS
$res=array();
for($ln=0;$ln<$ln_max;++$ln){
for($cl=0;$cl<$cl_max;++$cl){
if($array[$ln][$cl]===0)continue;
if(!isset($res[$array[$ln][$cl]]))$res[$array[$ln][$cl]]=1;
else $res[$array[$ln][$cl]]++;
}}
//get largest shape
$max = max($res);
$shape_value_max = array_search ($max, $res);
//get smallest shape
$min = min($res);
$shape_value_min = array_search ($min, $res);
// recursive function: detect connecting cells
function look_around($ln,$cl,$ln_max,$cl_max,$nr,&$array){
//create mini array
$mini=mini($ln,$cl,$ln_max,$cl_max);
if($mini===false)return false;
//loop surrounding cells
foreach($mini as $v){
if($array[$v[0]][$v[1]]===0){continue;}
if($array[$v[0]][$v[1]]!==$nr){
// set shape_nr of connecting cell
$array[$v[0]][$v[1]]=$nr;
// follow the shape
look_around($v[0],$v[1],$ln_max,$cl_max,$nr,$array);
}
}
return $nr;
}
// CREATE ARRAY WITH THE 9 SURROUNDING CELLS
function mini($ln,$cl,$ln_max,$cl_max){
$look=[];
$mini=[[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]];
foreach($mini as $v){
if( $ln + $v[0] >= 0 &&
$ln + $v[0] < $ln_max &&
$cl + $v[1] >= 0 &&
$cl + $v[1] < $cl_max
){
$look[]=[$ln + $v[0], $cl + $v[1]];
}
}
if(count($look)===0){return false;}
return $look;
}
Here's a fiddle
I can only think of a few minor improvements:
Keep a linked list of the not empty fields. In step 2 you do not need to touch n² matrix-elements, you only need to touch the ones in your linked list. Which might be much less depending how sparse your matrix is.
You only need to compare to the right, right-down, left-down and down directions. Otherwise The other directions are already checked from the former row/column. What I mean: When I am greater that my right neighbour, I can already change the number of the right neighbour. (same for down and right-down). This halfs the number of compairs.
If your array size isn't huge and memory won't be a problem maybe a recursive solution would be faster. I found a c++ algorithm that does this here:
https://www.geeksforgeeks.org/find-length-largest-region-boolean-matrix/

How to filter out numbers in an array PHP

I don't know why I can't get my head around this problem. Probably because I should be getting rest, but I have to at least solve this first.
Lets say that I let people rent my bicycles.
I have 4 of them.
Each of them are numbered 1, 2, 3 & 4.
Today no. 1 & 3 was already rented(which is saved in the database)
The third customer arrives and I wanted to see the "available"
numbers, which are supposed to be 2 & 4.
$bicycles = array(1, 2, 3, 4);
$rent = array(1,3);
$available = array();
How to save the available numbers in $available and at the same time count the number of available bicycles?
The problem actually has more factors involved, but I'll be okay if I get to settle this first. Hopefully.
array_diff is a better way to go, but this is easier to follow.
// Your bikes
$Bikes = array(1, 2, 3, 4);
// Rented bikes
$Rented = array(2, 3);
// Create a result array that we will fill as we loop
$Available = array();
// Find the difference manually by looping
foreach($Bikes as $Bike){
// If the bike isn't rented, add it to the Available array
if(!in_array($Bike, $Rented)) array_push($Available, $Bike);
}
var_dump($Available); // should contain 1 and 4
You can use the function array_diff() to return the difference between two arrays, and count() or sizeof() to return the number of elements in an array.

Assigning Variable to Range of Numbers with PHP

I have a simple problem (I hope). I've got an input form that takes, as input, 2 numbers, a start ($tag_start_01) and an end value ($tag_end_01).
I want to generate a string of numbers between those inputs, and assign them to a new variable ($tag_range_01), so that I can write the string to a TXT file.
The foundation of the code here, works:
foreach (range($tag_start_01, $tag_end_01, 1) as $tag_range_01) {
echo "$tag_range_01, ";
}
This will generate (assuming start is 1 and end is 10):
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
How do I assign this resulting set of numbers to the variable $tag_range_01 as a string?
You can do it without using foreach loop :
$tag_range_01 = implode(', ',range($tag_start_01, $tag_end_01, 1));

Check to see if database contains array values

I am new to writing server code, anyway I have a SQL DB that contains a list of numbers, I am wanting to check to see if an array that contains a list of numbers has any overlap with the DB.
Database:
ID Number
1 3
2 5
3 7
4 11
5 13
6 19
For example, in PHP/psuedocode:
$numbers = $_REQUEST['NUMBERS'] // array of numbers i.e. [3, 7, 20, 54]
This is what I'm looking for:
echo json_encode($result) // returns [3, 7]
Just do a query selecting the rows containing the numbers from the request:
$numbers = implode(',', $_REQUEST['NUMBERS']);
$query = "SELECT Number FROM TableName WHERE Number IN ($numbers)";

Categories