PHP reorder array keys from certain key onward, looping back around - php

So I have an array:
$array = array('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
Obviously they're indexed 0-6.
I want to feed in a specific key index, and then reorder the array, beginning with that key, then going through the rest in the same order, like so:
print_r(somefunction(3, $array));
which would print this:
array
(
'0'=>'Wed',
'1'=>'Thu',
'2'=>'Fri',
'3'=>'Sat',
'4'=>'Sun',
'5'=>'Mon',
'6'=>'Tue'
)
Is there a core function that would do this, or does anyone have a quick solution?
UPDATE
Here's my final function, slightly bigger in scope than my question above, which utilizes AbraCadaver's answer:
public static function ordered_weekdays($format = 'abr')
{
$array = $format == 'full' ? array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday') : array('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
return array_merge(array_splice($array, get_option('start_of_week'), count($array)-1), $array);
}
Because it's a nice one-liner, I didn't need to make it a separate function.

I've done this before and thought it was simpler than this, but here is what my brain says at the moment:
$index = 3;
$array = array_merge(array_splice($array, $index, count($array)-1), $array);

Try something along these lines...
function reorder($x,$y)
{
$c = count($y);
for ($i=0; $i<$c; $i++)
{
$newArray[$i] = $y[$x];
$x++;
if ($x > $c) $x = 0;
}
return($newArray);
}

function somefunction($n, array $a) {
$x = array_slice($a, 0, $n);
$y = array_slice($a, $n);
return array_merge($y, $x);
}
// forget this: uneccessary looping...
function somefunction($n, array $a) {
for($i = 0; $i < $n; $i++) {
array_push($a, array_shift($a));
}
return $a;
}

Related

How to replace a value in array by another different value in PHP?

I'm trying to find a way to replace any duplicated value but the only solution I have found so far is array_unique which doesn't really work for me as I need the duplicate to be replaced by another number which itself is not a duplicate.
function generate_random_numbers($rows, $delimiter)
{
$numbers = array();
for($i = 0; $i < $delimiter; $i++)
{
$numbers[$i] = rand(1, $rows);
if(in_array($i, $numbers))
{
$numbers[$i] = rand(1, $row);
}
}
return $numbers;
}
$numbers = generate_random_numbers(20, 10);
print_r($numbers);
would anyone help me out on this one please?
You can do this way easier and faster.
Just create an array for all possible numbers with range(). Then shuffle() the array and take an array_slice() as big as you want.
<?php
function generate_random_numbers($max, $amount) {
if($amount > $max)
return [];
$numbers = range(1, $max);
shuffle($numbers);
return array_slice($numbers, 0, $amount);
}
$numbers = generate_random_numbers(20, 10);
print_r($numbers);
?>
And if you want to get 490 unique elements from a range from 1 - 500, 10'000 times:
My version: ~ 0.7 secs
Your version: Order 2 birthday cakes, you will need them.
You are inserting a random number and then, if it is already in the array (which it MUST be because you just inserted it), you use a new random number, which might be a duplicate. So, you have to get a number that is not a duplicate:
do {
$num = rand(1,$rows);
} while(!in_array($num, $numbers));
Now, you know that $num is not in $numbers, so you can insert it:
$numbers[] = $num;
You were pretty close.
The if-clause needs to be a loop, to get new random number.
(Also your in_array was slightly wrong)
function generate_random_numbers($rows, $delimiter) {
$numbers = array();
for($i = 0; $i < $delimiter; $i++) {
do {
$number = rand(1, $rows);
}
while(in_array($number, $numbers));
$numbers[] = $number;
}
return $numbers;
}

adding string to all but last item in array

I have an array and I'd like to add a string to each item in the array, apart from the last item.
Any ideas how I'd do this?
Thanks
This should do it for both numerically-indexed arrays and associative arrays:
$i = 0;
$c = count($array);
foreach ($array as $key => $val) {
if ($i++ < $c - 1) {
$array[$key] .= 'string';
}
}
If your array is numerically indexed, a simple loop does the job.
for ($i = count($array) - 2; $i >= 0; $i--) {
$array[$i] = $array[$i] . $stringToAppend;
}
I don't think there is a native command for this.
Just do it the traditional way.
// Your array.
$MyArray = array("Item1","Item2","Item3");
// Check that we have more than one element
if (count($MyArray) > 1) {
for ($n=0; $n<count($MyArray)-1; $n++) {
$MyArray[$n] .= " Appended string";
}
}
The code is from the top of my head, so maybe some tweeking might do he trick.
Well a simple for loop would be the obvious thing I guess.
for ( $i=0; $i < count( $myArray )-1; $i++ )
{
$myArray[$i] = "Hey look a string";
}
But then you might also just use array_fill to do a similar job:
array_fill( 0, $sizeOfArray, "Hey look a string" )
Then you can just set the last value to be whatever you want it to be.
EDIT: If by "add a string to each item" you mean you already have a value in the array and you want to append a string, then I would use my first suggestion with $myArray[$i] .= "Hey look a string"; instead of the simple assignment.
$array =array();
$statement = null;
for ($j= 0;$j<count($array);$j++) {
if ($j === count($array)-1) {
$statement .= $array[$j];
} else {
$statement .= $array[$j].' OR ';
}
}

How do I select random values from an array in PHP?

I have an array of objects in PHP. I need to select 8 of them at random. My initial thought was to use array_rand(array_flip($my_array), 8) but that doesn't work, because the objects can't act as keys for an array.
I know I could use shuffle, but I'm worried about performance as the array grows in size. Is that the best way, or is there a more efficient way?
$result = array();
foreach( array_rand($my_array, 8) as $k ) {
$result[] = $my_array[$k];
}
$array = array();
shuffle($array); // randomize order of array items
$newArray = array_slice($array, 0, 8);
Notice that shuffle() function gives parameter as a reference and makes the changes on it.
You could use array_rand to pick the keys randomly and a foreach to gather the objects:
$objects = array();
foreach (array_rand($my_array, 8) as $key) {
$objects[] = $my_array[$key];
}
What about?:
$count = count($my_array);
for ($i = 0; $i < 8; $i++) {
$x = rand(0, $count);
$my_array[$x];
}
I just found this in our code and was hoping to find a more readable solution:
$rand = array_intersect_key($all, array_flip(array_rand($all, $count)));
You can get multiple random elements from an array with this function:
function getRandomElements(array $array): array
{
$result = [];
$count = count($array);
for ($i = 0; $i < rand(0, $count); $i++) {
$result[] = rand(0, $count);
}
$result = array_unique($result);
sort($result);
return $result;
}

How to get the length of longest string in an array

Say I have this array:
$array[] = 'foo';
$array[] = 'apple';
$array[] = '1234567890;
I want to get the length of the longest string in this array. In this case the longest string is 1234567890 and its length is 10.
Is this possible without looping through the array and checking each element?
try
$maxlen = max(array_map('strlen', $ary));
Sure:
function getmax($array, $cur, $curmax) {
return $cur >= count($array) ? $curmax :
getmax($array, $cur + 1, strlen($array[$cur]) > strlen($array[$curmax])
? $cur : $curmax);
}
$index_of_longest = getmax($my_array, 0, 0);
No loop there. ;-)
A small addition to the ticket. I came here with a similar problem: Often you have to output just the longest string in an array.
For this, you can also use the top solution and extend it a little:
$lengths = array_map('strlen', $ary);
$longestString = $ary[array_search(max($lengths), $lengths)];
Loop through the arrays and use strlen to verify if the current length is longer than the previous.. and save the index of the longest string in a variable and use it later where you need that index.
Something like this..
$longest = 0;
for($i = 0; $i < count($array); $i++)
{
if($i > 0)
{
if(strlen($array[$i]) > strlen($array[$longest]))
{
$longest = $i;
}
}
}
This way you can find the shortest (or longest) element, but not its index.
$shortest = array_reduce($array, function ($a, $b) {
if ($a === null) {
return $b;
}
return strlen($a) < strlen($b) ? $a : $b;
});

Sorting x and y coordinates in an array in PHP most efficently?

Currently I have an array that contains x and y coordinates of various positions.
ex.
$location[0]['x'] = 1; $location[0]['y'] = 1
This indicates id 0 has a position of (1,1).
Sometimes I want to sort this array by x, and other times by y.
Currently I am using array_multisort() to sort my data, but I feel this method is inefficient since every time before I sort, I must make a linear pass through the $location array just to build the index (on the x or y key) before I can invoke the array_multisort() command.
Does anyone know a better way to do this? Perhaps it is a bad idea even to store the data like this? Any suggestions would be great.
You could use usort() which lets you choose how your array elements are compared.
// sort by 'y'
usort($location, 'cmp_location_y');
// or sort by 'x'
usort($location, 'cmp_location_x');
// here are the comparison functions
function cmp_location_x($a, $b) {
return cmp_location($a, $b, 'x');
}
function cmp_location_y($a, $b) {
return cmp_location($a, $b, 'y');
}
function cmp_location($a, $b, $key) {
if ($a[$key] == $b[$key]) {
return 0;
} else if ($a[$key] < $b[$key]) {
return -1;
} else {
return 1;
}
}
You want to keep using multisort.
I made a quick benchmark of usort and array_multisort. Even at a count of only 10 multisort with building an index is faster than usort. At 100 elements it's about 5 times faster. At around 1000 elements improvement levels off right at a magnitude faster. User function calls are just too slow. I'm running 5.2.6
$count = 100;
for ($i = 0; $i < $count; $i++)
{
$temp = array('x' => rand(), 'y' => rand());
$data[] = $temp;
$data2[] = $temp;
}
function sortByX($a, $b) { return ($a['x'] > $b['x']); }
$start = microtime(true);
usort($data, "sortByX");
echo (microtime(true) - $start) * 1000000, "<br/>\n";
$start = microtime(true);
foreach ($data2 as $temp)
$s[] = $temp['x'];
array_multisort($s, SORT_NUMERIC, $data2);
echo (microtime(true) - $start) * 1000000, "<br/>\n";
PHP currently doesn't have an array_pluck function like ruby. Once it does you can replace this code
foreach ($data2 as $temp)
$s[] = $temp['x'];`
with
$s = array_pluck('x', $data2);
Something like what jcinacio said. With this class you can store and sort all sorts of data really, not just locations in different dimensions. You can implement other methods like remove etc as needed.
class Locations {
public $locations = array();
public $data = array();
public $dimensions = 2;
public function __construct($dimensions = null)
{
if (is_int($dimensions))
$this->dimensions = $dimensions;
}
public function addLocation()
{
$t = func_num_args();
if ($t !== $this->dimensions)
throw new Exception("This Locations object has {$this->dimensions} dimensions");
$args = func_get_args();
for ($i = 0; $i < $t; $i++)
$this->locations[$i][] = $args[$i];
return $this;
}
public function sortByDimension($dimension = 1)
{
if ($dimension > $this->dimensions)
throw new Exception("Wrong number of dimensions");
--$dimension;
$params[] = &$this->locations[$dimension];
for ($i = 0, $t = $this->dimensions; $i < $t; $i++) {
if ($i === $dimension)
continue;
$params[] = &$this->locations[$i];
}
call_user_func_array('array_multisort', $params);
return $this;
}
}
test data:
$loc = new Locations(3);
$loc
->addLocation(1, 1, 'A')
->addLocation(2, 3, 'B')
->addLocation(4, 2, 'C')
->addLocation(3, 2, 'D')
;
$loc->sortByDimension(1);
var_dump($loc->locations);
$loc->sortByDimension(2);
var_dump($loc->locations);
keeping the arrays and the multisort you have, changing the structure to something like the following would eliminate the need for a previous pass:
$locations = array(
'x' => $x_coordinates,
'y' => $y_coordinates,
'data' => $data_array
);
then just use the array_multisort() on all columns.

Categories