PHP return next and previous array items - php

I have the following simple array and php
$my_array=array("a"=>"red","b"=>"green","c"=>"blue","d"=>"purple","e"=>"yellow");
$match_key = array_search("blue",$my_array);
echo $match_key;
I would like to create two variables that are the array item either side of $match_key. So in the example above I am trying to end up with...
$previous = 'green';
$next = 'purple';
What is the best way to tackle this?

If you have no way of changing your array structure, you could do the following by "creating" a new array with just the values of the original array, via array_values()
$vals = array_values($my_array);
$match_key = array_search("blue", $vals);
echo "PREV: ". $vals [($match_key - 1)] . "\n";
echo "CURR: ". $vals[$match_key] ."\n";
echo "NEXT: ". $vals [($match_key + 1)] . "\n";
Which returns:
PREV: green
CURR: blue
NEXT: purple
Now you'll need to do key handling/etc to ensure the code doesn't throw any errors and handles your keys in a subtle way.
There are various other ways (inspired by this post) that harnesses in-built functions, although seemingly taking longer to process:
$match_key = array_search("blue", $my_array);
// loop through and set the array pointer to the $match_key element
while (key($my_array) !== $match_key) next($my_array);
$current = $my_array[$match_key];
$prev = prev($my_array);
next($my_array); // set the array pointer to the next elem (as we went back 1 via prev())
$next = next($my_array);
Which returns the previous, current & next as below:
CURRENT: blue
PREVIOUS: green
NEXT: purple

Using array_values() is the way to go. This creates a new indexed array in the same order as your original array.
Then you can search that for your value using array_search() which returns the numeric index. Then just +1 for the next and -1 for the previous.
Of course you may want to verify that the value you are searching for actually exists. If so, then ensure index+1 and index-1 also exist and set as null if they don't.
Something like this:
$my_val = 'blue';
$int_indexes = array_values($my_array); // store all values into integer indexed array
if ($index = array_search($my_val, $int_indexes)) { // don't set prev-next if value not found
$prev = array_key_exists($index - 1, $int_indexes) ? $int_indexes[$index - 1] : null;
$next = array_key_exists($index + 1, $int_indexes) ? $int_indexes[$index + 1] : null;
}
echo "previous: $prev" . '<br>';
echo "this: $my_val" . '<br>';
echo "next: $next";
Gives you results:
// previous: green
// this: blue
// next: purple
And if your searched value is at the beginning or end, no worries, you just get a null value. And it your searched value isn't found, no worries, you just get 2 null values.

Related

How do I move a group of items in a PHP array below the next group of items?

In an Array with normal numerical keys ( $file_array_for_editing ), I want to move a set of consecutive X number of values below the next set of X values.
Example: If a group of X values is 10, then in an Array of 50, I have 5 sets of 10 values. I want to move the 10 values in set 3 - below the 10 values in set 4.
So that : Set1(10 values) , Set2(10 values) , Set3(10 values) , Set4(10 values) , Set5(10 values)
Becomes: Set1(10 values) , Set2(10 values) , Set4(10 values) , Set3(10 values) Set5(10 values)
Since I don't know a better way, this is how I have done it now - by what I believe is switching the values:
$file_array_for_editing = [];
for($i=1; $i <= 50; $i++) {
$file_array_for_editing[] = $i;
}
$number_in_one_set = 10 ;
$set_number_to_move = 3 ;
$f = $file_array_for_editing ;
$s = ($set_number_to_move - 1) * $number_in_one_set ; // (3 - 1) * 10 = 20
list(
$f[$s+0],$f[$s+1],$f[$s+2],$f[$s+3],$f[$s+4],$f[$s+5],$f[$s+6],$f[$s+7],$f[$s+8],$f[$s+9],$f[$s+10],$f[$s+11],$f[$s+12],$f[$s+13],$f[$s+14],$f[$s+15],$f[$s+16],$f[$s+17],$f[$s+18],$f[$s+19]
) =
[$f[$s+10],$f[$s+11],$f[$s+12],$f[$s+13],$f[$s+14],$f[$s+15],$f[$s+16],$f[$s+17],$f[$s+18],$f[$s+19],$f[$s+0],$f[$s+1],$f[$s+2],$f[$s+3],$f[$s+4],$f[$s+5],$f[$s+6],$f[$s+7],$f[$s+8],$f[$s+9]];
$file_array_for_editing = $f ;
At the end, the numerical keys stay properly in order, from 0 to 49.
I need help finding a way to do this where I can vary the $number_in_one_set
If possible, I would appreciate help finding a solution where it is clearly apparent what is being done, so that after a year, when I look at the code again, it will be easy to understand. (as in, even now, I just vaguely understand why the list() above works)
Possibly following might help you on your way. You can change the 'sets' you'd like to switch using array $switch.
<?php
$arr = [];
for($i=1; $i <= 50; $i++) {
$arr[] = $i;
}
$set = 10; // each set has 10 items
$switch = [3, 4]; // switch element 3 vs. 4
$newArr = array_chunk($arr, $set); // chop array in chunks of size $set
// swap
$tmp = $newArr[$switch[0]]; // $temp=$newArr[3]
$newArr[$switch[0]] = $newArr[$switch[1]]; // $newArr[3]=newArr[4]
$newArr[$switch[1]] = $tmp; // $newArr[4]=$newArr[3]
$result = [];
array_walk_recursive($newArr, function($el) use (&$result) { $result[] = $el; }); // flatten array
EDIT
array_walk_recursive() applies the callback function (function($el)) to each element of nested array $newArr.
Each element of array $newArr, referenced by $el will be pushed into array $result, a flat indexed array.
Also, because the anonymous function (closure) writes to flat array $result which is defined in the parent scope, we need to employ the use language construct.
source manual: Closures may also inherit variables from the parent scope. Any such variables must be passed to the use language construct.
working demo
#jibsteroos - I really like the method you provided (which #CBroe also suggested) - reason being that it allows any two sets anywhere within the original array to be swapped.
After some thought, I find I prefer using the method below, even though it is a little long winded - reason being my use case is only to exchange a set with the one below it.
<?php
$arr = []; // Setting up a sample array
for($i=1; $i <= 50; $i++) {
$arr[] = $i;
}
$set_size = 10 ; // 10 items per set
$set = 3 ; // set to move down
$set_to_move = ($set - 1) * $set_size; // start position of this set in the array - 20
print_r($arr) ;
echo '<hr>';
$slice1 = array_slice($arr,0,$set_to_move);
print_r($slice1) ; // from the start of the array - to the start of the set to move
echo '<hr>';
$slice2 = array_slice($arr,$set_to_move,$set_size);
print_r($slice2) ; // the set to move
echo '<hr>';
$slice3 = array_slice($arr,$set_to_move + $set_size,$set_size);
print_r($slice3) ; // the set after the set to move
echo '<hr>';
$slice4 = array_slice($arr,$set_to_move + (2 * $set_size));
print_r($slice4) ; // the rest of the array
echo '<hr>';
$arr_edited = array_merge($slice1,$slice3,$slice2,$slice4,);
print_r($arr_edited) ; // All 4 arrays combined in the new order
echo '<hr>';

how to access a json_decoded array with string keys/indizes via integer numbers [duplicate]

What's the best way to determine the first key in a possibly associative array? My first thought it to just foreach the array and then immediately breaking it, like this:
foreach ($an_array as $key => $val) break;
Thus having $key contain the first key, but this seems inefficient. Does anyone have a better solution?
2019 Update
Starting from PHP 7.3, there is a new built in function called array_key_first() which will retrieve the first key from the given array without resetting the internal pointer. Check out the documentation for more info.
You can use reset and key:
reset($array);
$first_key = key($array);
It's essentially the same as your initial code, but with a little less overhead, and it's more obvious what is happening.
Just remember to call reset, or you may get any of the keys in the array. You can also use end instead of reset to get the last key.
If you wanted the key to get the first value, reset actually returns it:
$first_value = reset($array);
There is one special case to watch out for though (so check the length of the array first):
$arr1 = array(false);
$arr2 = array();
var_dump(reset($arr1) === reset($arr2)); // bool(true)
array_keys returns an array of keys. Take the first entry. Alternatively, you could call reset on the array, and subsequently key. The latter approach is probably slightly faster (Thoug I didn't test it), but it has the side effect of resetting the internal pointer.
Interestingly enough, the foreach loop is actually the most efficient way of doing this.
Since the OP specifically asked about efficiency, it should be pointed out that all the current answers are in fact much less efficient than a foreach.
I did a benchmark on this with php 5.4, and the reset/key pointer method (accepted answer) seems to be about 7 times slower than a foreach. Other approaches manipulating the entire array (array_keys, array_flip) are obviously even slower than that and become much worse when working with a large array.
Foreach is not inefficient at all, feel free to use it!
Edit 2015-03-03:
Benchmark scripts have been requested, I don't have the original ones but made some new tests instead. This time I found the foreach only about twice as fast as reset/key. I used a 100-key array and ran each method a million times to get some noticeable difference, here's code of the simple benchmark:
$array = [];
for($i=0; $i < 100; $i++)
$array["key$i"] = $i;
for($i=0, $start = microtime(true); $i < 1000000; $i++) {
foreach ($array as $firstKey => $firstValue) {
break;
}
}
echo "foreach to get first key and value: " . (microtime(true) - $start) . " seconds <br />";
for($i=0, $start = microtime(true); $i < 1000000; $i++) {
$firstValue = reset($array);
$firstKey = key($array);
}
echo "reset+key to get first key and value: " . (microtime(true) - $start) . " seconds <br />";
for($i=0, $start = microtime(true); $i < 1000000; $i++) {
reset($array);
$firstKey = key($array);
}
echo "reset+key to get first key: " . (microtime(true) - $start) . " seconds <br />";
for($i=0, $start = microtime(true); $i < 1000000; $i++) {
$firstKey = array_keys($array)[0];
}
echo "array_keys to get first key: " . (microtime(true) - $start) . " seconds <br />";
On my php 5.5 this outputs:
foreach to get first key and value: 0.15501809120178 seconds
reset+key to get first key and value: 0.29375791549683 seconds
reset+key to get first key: 0.26421809196472 seconds
array_keys to get first key: 10.059751987457 seconds
reset+key http://3v4l.org/b4DrN/perf#tabs
foreach http://3v4l.org/gRoGD/perf#tabs
key($an_array) will give you the first key
edit per Blixt: you should call reset($array); before key($an_array) to reset the pointer to the beginning of the array.
You could try
array_keys($data)[0]
For 2018+
Starting with PHP 7.3, there is an array_key_first() function that achieve exactly this:
$array = ['foo' => 'lorem', 'bar' => 'ipsum'];
$firstKey = array_key_first($array); // 'foo'
Documentation is available here. 😉
list($firstKey) = array_keys($yourArray);
If efficiency is not that important for you, you can use array_keys($yourArray)[0] in PHP 5.4 (and higher).
Examples:
# 1
$arr = ["my" => "test", "is" => "best"];
echo array_keys($arr)[0] . "\r\n"; // prints "my"
# 2
$arr = ["test", "best"];
echo array_keys($arr)[0] . "\r\n"; // prints "0"
# 3
$arr = [1 => "test", 2 => "best"];
echo array_keys($arr)[0] . "\r\n"; // prints "1"
The advantage over solution:
list($firstKey) = array_keys($yourArray);
is that you can pass array_keys($arr)[0] as a function parameter (i.e. doSomething(array_keys($arr)[0], $otherParameter)).
HTH
Please find the following:
$yourArray = array('first_key'=> 'First', 2, 3, 4, 5);
$keys = array_keys($yourArray);
echo "Key = ".$keys[0];
Working Example:
$myArray = array(
2 => '3th element',
4 => 'first element',
1 => 'second element',
3 => '4th element'
);
echo min(array_keys($myArray)); // return 1
This could also be a solution:
$yourArray = array('first_key'=> 'First', 2, 3, 4, 5);
$first_key = current(array_flip($yourArray));
echo $first_key;
I have tested it and it works.
Working Code.
To enhance on the solution of Webmut, I've added the following solution:
$firstKey = array_keys(array_slice($array, 0, 1, TRUE))[0];
The output for me on PHP 7.1 is:
foreach to get first key and value: 0.048566102981567 seconds
reset+key to get first key and value: 0.11727809906006 seconds
reset+key to get first key: 0.11707186698914 seconds
array_keys to get first key: 0.53917098045349 seconds
array_slice to get first key: 0.2494580745697 seconds
If I do this for an array of size 10000, then the results become
foreach to get first key and value: 0.048488140106201 seconds
reset+key to get first key and value: 0.12659382820129 seconds
reset+key to get first key: 0.12248802185059 seconds
array_slice to get first key: 0.25442600250244 seconds
The array_keys method times out at 30 seconds (with only 1000 elements, the timing for the rest was about the same, but the array_keys method had about 7.5 seconds).
$arr = array('key1'=>'value1','key2'=>'value2','key3'=>'key3');
list($first_key) = each($arr);
print $first_key;
// key1
This is the easier way I had ever found. Fast and only two lines of code :-D
$keys = array_keys($array);
echo $array[$keys[0]];
The best way that worked for me was
array_shift(array_keys($array))
array_keys gets array of keys from initial array and then array_shift cuts from it first element value.
You will need PHP 5.4+ for this.
php73:
$array = ['a' => '..', 'b' => '..'];
array_key_first($array); // 'a'
array_key_last($array); // 'b';
http://php.net/manual/en/function.array-key-first.php
Since PHP 7.3.0 function array_key_first() can be used.
There are several ways to provide this functionality for versions prior to PHP 7.3.0. It is possible to use array_keys(), but that may be rather inefficient. It is also possible to use reset() and key(), but that may change the internal array pointer. An efficient solution, which does not change the internal array pointer, written as polyfill:
<?php
if (!function_exists('array_key_first')) {
function array_key_first(array $arr) {
foreach($arr as $key => $unused) {
return $key;
}
return null;
}
}
?>
Re the #Blixt answer, prior to 7.3.0, this polyfill can be used:
if (!function_exists('array_key_first')) {
function array_key_first(array $array) {
return key(array_slice($array, 0, 1, true));
}
}
This will work on all PHP versions
$firstKey = '' ;
//$contact7formlist - associative array.
if(function_exists('array_key_first')){
$firstKey = array_key_first($contact7formlist);
}else{
foreach ($contact7formlist as $key => $contact7form ){
$firstKey = $key;
break;
}
}
A one-liner:
$array = array('key1'=>'value1','key2'=>'value2','key3'=>'key3');
echo key( array_slice( $array, 0, 1, true ) );
# echos 'key1'
Today I had to search for the first key of my array returned by a POST request. (And note the number for a form id etc)
Well, I've found this:
Return first key of associative array in PHP
http://php.net/key
I've done this, and it work.
$data = $request->request->all();
dump($data);
while ($test = current($data)) {
dump($test);
echo key($data).'<br />';die();
break;
}
Maybe it will eco 15min of an other guy.
CYA.
I think the best and fastest way to do it is:
$first_key=key(array_slice($array, 0, 1, TRUE))
array_chunk split an array into chunks, you can use:
$arr = ['uno'=>'one','due'=>'two','tre'=>'three'];
$firstElement = array_chunk($arr,1,true)[0];
var_dump($firstElement);
You can play with your array
$daysArray = array('Monday', 'Tuesday', 'Sunday');
$day = current($transport); // $day = 'Monday';
$day = next($transport); // $day = 'Tuesday';
$day = current($transport); // $day = 'Tuesday';
$day = prev($transport); // $day = 'Monday';
$day = end($transport); // $day = 'Sunday';
$day = current($transport); // $day = 'Sunday';
To get the first element of array you can use current and for last element you can use end
Edit
Just for the sake for not getting any more down votes for the answer you can convert you key to value using array_keys and use as shown above.
use :
$array = ['po','co','so'];
echo reset($array);
Result : po

php array insert and print

This is a part of my PHP program.
//for example: $rec_count = 30
$totalpages=(int)$rec_count/10;
$index=0;
$pageslink[$totalpages]='';
while($index <= $totalpages ){
$pageslink['index']=$index;
echo '<br>Index: '.$index.'<br>';
echo '<br>Page '.$pageslink['index'].' ';
$index++;
}
print_r($pageslink);
It comes out like this:
Index: 0
Page 0
Index: 1
Page 1
Index: 2
Page 2
Index: 3
Page 3 Array ( [3] => [index] => 3 )
Its supposed to be pageslink[0] = 1; pageslink[1 ]= 2; pageslink[3] = 3; But When I print_r() the pageslink array , only 3 as a value. I've been trying to find out why only 3 is inserted as value in array.
I am a beginner, so thank you in advance for your help. It will be much appreciated.
In the short version of this answer, arrays in PHP start counting from 0, not 1. So on the first loop it would be 0 and the second loop it would be 1 and so on.
You're using
$pageslink['index'] = $index;
Meaning you set the item with the named key 'index' in your array to the value of your variable $index, instead of using $index as your key.
In PHP (and many other languages) you can refer to an item in an array with its index number (0, 1, 2, etc.) or by a word (named key).
For example:
$myArray = ['John', 'London'];
echo $myArray[0]; // John
echo $myAray[1]; // London
or
$myArray = ['name' => 'John', 'city' => 'london'];
echo $myArray['name']; // John
echo $myArray['city']; // London
What you are doing now is setting the same item in your array (the item you're calling index) to a new value every loop, overwriting its old value. So after all the loops you'll only have the last value saved.
You want something like this:
$pageslink[$index] = $index + 1;
Which will translate to:
$pageslink[0] = 1; // first loop
$pageslink[1] = 2; // second loop
$pageslink[2] = 3; // third loop
By the way, a for loop would be cleaner in your example code:
$rec_count = 30
$totalpages=(int)$rec_count/10;
$pageslink = array(); // this is how to create an array, not with ''
for($i=0;i<$totalpages;$i++){
$pageslink[] = $i;
}
print_r($pageslink);
You over complicate the code here, try:
$totalpages=(int)$rec_count/10;
$index=0;
$pageslink = array();
while($index <= $totalpages ){
$pageslink[]=$index+1;
echo '<br>Index: '.$index.'<br>';
echo '<br>Page '.$pageslink[$index].' ';
$index++;
}
print_r($pageslink);
But this code is very weird. You just create array of n elements.
Could you explain what do you try to achieve here?

multi-dimension array duplicate - performance

What is the best way to check if an multi-dimension array contains 2 or more equal value and only return the first one .
ex : i have an array of people that contain
[0][firstName] = 'John';
[0][lastName] = 'Doe';
[N][firstName] = 'Marco';
[N][lastName] = 'Polo';
[120][firstName] = 'John';
[120][lastName] = 'Doe';
Should detect that the index 120 is a duplicate and remove it .
I'm looking for the best performance , i don't want to loop on the array and check every time if i have the value or not .
Is there something faster ?
It is the element distinctness problem which is basically O(NlogN) via sorting and iterating (after sorting, duplicates will be adjacent to each other - so easy to detect them)
However, it can be done also in O(N) on average and with O(N) additional space by storing all elements to a hash table while iterating, and breaking if an element already exists.
You might also want to store the original index of each element if you will later need it (and don't use the index as key).
pseudo code:
map <- empty hash map
for each element e with idx i in list (in ascending order of i):
if (map.contains(e)):
e is a dupe, the first element is in index map.get(e)
else:
map.add(e,i)
You can try
// Generate Possible name with duplicate
$names = array("John","Doe","Polo","Marco","Smith");
$array = array();
for($i = 0; $i < 20; $i ++) {
$key = mt_rand(0, 1000);
$array[$key]["firstName"] = $names[array_rand($names)];
$array[$key]["lastName"] = $names[array_rand($names)];
}
// Start Sorting process
ksort($array);
// Start Storage
$data = $hash = array();
// Loop and porpulate new array
foreach ( $array as $k => $v ) {
$h = sha1($v['firstName'] . $v["lastName"]);
isset($hash[$h]) or $data[$k] = $v and $hash[$h] = 1;
}
var_dump($data);

PHP: push variable number of elements to associative array

A folder on my server holds a variable number of images. I'm working on a PHP script that is intended to retrieve the entire list of files there (a list of filenames) and create an associative array like so:
$list = array(1=>"image1.png", 2=>"image2.png", ...);
Basically, the list vector starts as empty and when a new image is found, its name has to be added to the list, with an incremented index: i=>"image[i].png"
How do I go about achieving this? Or in other words, how do I push a new element to my array?
I'm not sure why you are referring to this as an associative-array, but if you want to add somethign to an array, do it like this
$list = array();
$list[] = "image1.png";
$list[] = ....;
$list[] = "imagei.png";
If you want to push new item to your array, try with:
$list[] = "image" + ( count($list) + 1 ) + ".png";
If your items' indexes starts with 1, add +1 in the name as described above. If you are starting from 0 as it is natural behaviour, skip it and use as described below:
$list[] = "image" + count($list) + ".png";
So you are in fact re-implementing glob()?
$list = glob('/path/to/images/*.png');
If you are really want to reimplement it yourself
$i = 0;
$list = array();
while (file_exists('/path/to/image' . (++$i) . '.png'))
$list[$i] = "image$i.png";

Categories