How can I loop through the entire array starting from any position? - php

So I have an array like this:
$arr = [0, 1, 2];
Now I get a user input, e.g.
$input = 1;
Depending on that input I want to loop through all array elements starting from the position of that input.
Example:
//Array: [0, 1, 2]
Input: 0 Output: 012
Input: 1 Output: 120
Input: 2 Output: 201
I don't know much about PHP so I tried a simple for loop:
for($x = 1; $x <= 2; $x++)
{
echo $x;
}
But obviously this doesn't work, so I'm stuck from where I have to go from here.

So what you want to do is create an ArrayIterator.
Then set the position of the iterator with ArrayIterator::seek() depending on which input you get. You can get the position easily with array_search():
$it->seek(array_search($input, $arr));
(If the input isn't found in the array array_search() simply returns FALSE, which then gets used as 0, means you just loop through the array)
Then you can simply loop through the amount of elements you have in the array with a for loop starting from the set position. And if you hit the end of the array you just rewind it:
//End of array?
if(!$it->valid()){
//Start again
$it->rewind();
}
Code
<?php
$arr = [0, 1, 2];
$input = 1;
$it = new ArrayIterator($arr);
$it->seek(array_search($input, $arr));
for($i = 0, $length = count($arr); $i < $length; $i++){
if(!$it->valid()){
$it->rewind();
}
echo $it->current();
$it->next();
}
?>
output:
120

foreach( [1,2,0] as $num ){
echo $num;
}

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.

How can I compare a loop value to an array value that is not sequentially the same?

I have a loop from 1 to 4, and I have an array which contain 1,2, and 4, but misses the number 3. How do I put or replace the missing 3 into 0 as my only thought to solve my problem, or get all the same values and then compare both sides? Because I need to compare both sides if it's same or not.
With this code, I'm getting the error: "undefined offset 3".
$a = array(1,2,4);
for ($i=1; $i <= 4; $i++) {
if ($i==$a[$i]) {
echo 'true';
} else {
false;
}
}
Is there other way to compare all those that have same value like
1 & 1 = true
2 & 2 = true
3 & = false
4 & 4 = true
And display something like
1. true
2. true
3. false
4. true
Probably the most straightforward way is to use in_array().
$a = [1, 2, 4];
for ($i = 1; $i <= 4; $i++) {
echo $i.'. '.(in_array($i, $a) ? 'true' : 'false').PHP_EOL;
}
Here is a working example.
Something like that :
$a = array(1,2,4);
$flipped = array_flip($a);
for($i = 1; $i <= 4; $i++){
$res[$i]="false";
if(array_key_exists($i, $flipped)){
$res[$i] = "true";
}
}
foreach($res as $key=>$value){
echo $key.". ".$value."<br/>";
}
The values in your array: $a = array(1, 2, 4) will not correspond to the $i in your for loop when you use $a[$i], because the value inside the square brackets refers to the key of the array, not to the value.
An array in PHP is an ordered map, with keys corresponding to values. When you define an array of values without assigning keys, like $a = array(1, 2, 4), PHP automatically creates integer keys for each of the values, beginning with zero, so in effect you are creating this array:
[0 => 1, 1 => 2, 2 => 4]
With the code you showed, you should be getting an undefined offset notice for 4 as well as 3.
If your array is sorted, one way to check for missing elements in your sequence is to check the current value of the array for each increment of your for loop, and move to the next element when a value matches.
$a = array(1,2,4);
for ($i=1; $i <= 4; $i++) {
if (current($a) == $i){
echo "$i: true".PHP_EOL;
next($a);
} else {
echo "$i: false".PHP_EOL;
}
}
The array must be sorted for this to work. If it is not in order as it is in your example, you can sort it with sort($a);.

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

How to make PHP array value equal to each other faster

let say I have an array of this values:
$arr = array(190, 2215, 2, 61);
after I run my code with 694 loops, I got this final values:
Array
(
[0] => 696
[1] => 696
[2] => 696
[3] => 696
)
how can I make the process faster and much better?? I only can increase or decrease the value by 1
Below are my codes.
<?php
echo '<pre>';
$arr = array(190, 2215, 2, 61);
sort($arr);
print_r($arr);
$arrLength = count($arr);
$counter = 0;
loop:
$counter++;
for($i=0; $i<$arrLength; $i++){
if($arr[$i] < $arr[$arrLength-1] && $arr[$arrLength-1] != $arr[$arrLength-2]) {
$arr[$i]++;
$arr[$arrLength-1]--;
}else if($arr[$i] < $arr[$arrLength-1] && $arr[$arrLength-1] == $arr[$arrLength-2]) {
$arr[$i]++;
}
}
if($arr[0] != $arr[$arrLength-1]) goto loop;
print_r($arr);
print_r($counter);
?>
Your code just finds a weighted average between the two largest values in an array, and then sets everything to it (Second largest element has weight of the number of elements - 1, the largest element has weight 1). You can do this much more easily and faster like this:
<?php
echo '<pre>';
$arr = array(190, 2215, 2, 61);
sort($arr);
print_r($arr);
$arrLength = count($arr);
// Find weighted average of second largest element and largest element in array:
$avg = floor(($arr[$arrLength - 2] * ($arrLength - 1) + $arr[$arrLength - 1])/$arrLength);
// Only need this line if you need the end value of counter from your code
// $counter = $avg - $arr[0]; // (964 in this example)
$arr = array_fill(0, $arrLength, $avg);
print_r($arr);
?>
Note: if all you need is the number (696) then you don't need the array_fill line. Just use the $avg variable for whatever you need it for later.

php basic operations question

I have a array of say 50 elements. This array can be of size anything.
I want to have the first 10 elements of the array in a string.
I have the program as:
$array1= array("itself", "aith","Inside","Engineer","cooool","that","it","because");
$i=0;
for($f=0; $f < sizeof(array1); $f++)
{
$temparry = $temparry.array1[$f];
if(($f%10) == 0 && ($f !== 0))
{
$temparray[$i] = $temparray;
$i++;
}
}
==
so that at the end:
I get
temparray1= first 10 elements
temparray2 - next 10 elemnts...
I am not what I am missing in my loops.
After reading your comment, I think you want array_chunk [docs]:
$chunks = array_chunk($array1, 10);
This will create a multidimensional array with each element being an array containing 10 elements.
If you still want to join them to a string, you can use array_map [docs] and implode [docs]:
$strings = array_map('implode', $chunks);
This gives you an array of strings, where each element is the concatenation of a chunk.
This is something you can easily do with array_splice and implode.
Example:
<?php
$array = range(1, 50);
while ( $extracted = array_splice($array, 0, 10) )
{
// You could also assign this to a variable instead of outputting it.
echo implode(' ', $extracted);
}
all you are doing here is creating a temporary value and then deleting it. To save it into a string:
$myArray = array("itself", "aith","Inside","Engineer",
"cooool","that","it","because");
$myString = '';
for($i = 0; $i < 10; $i++) {
$myString .= $myArray[$i];
}
You could also run that inside of another for loop that would run through the entire array giving you ten-element increments.
Actually you can use arrray_slice and implode functions like this:
// put first 10 elements into array output
$output = array_slice($myArray, 10);
// implode the 10 elements into a string
$str = implode("", $output);
OP's fixed code as per comments below:
$array1= array("itself","aith","Inside","Engineer","cooool","that","it","because");
$temparry='';
$temparray = array();
for($f=0; $f < count($array1); $f++)
{
$temparry = $temparry.$array1[$f];
if(($f%3) == 0 && ($f !== 0))
{
$temparray[] = $temparry;
$temparry = '';
}
}
print_r($temparray);

Categories