I need to rewrite some Python code into PHP (don't hate me, a customer asked me to do so)
In Python you can do something like this:
// Python
numbers = [34.6, -203.4, 44.9, 68.3, -12.2, 44.6, 12.7]
positive = [int(n) for n in numbers if n > 0]
negative = [int(n) for n in numbers if n < 0]
But if you try something like this in PHP it doesn't work:
// PHP
$numbers = array(34.6, -203.4, 44.9, 68.3, -12.2, 44.6, 12.7);
$positive = array(intval($n) for $n in $numbers if $n > 0);
$negative = array(intval($n) for $n in $numbers if $n > 0);
Instead of doing something like:
<?php
$numbers = array(34.6, -203.4, 44.9, 68.3, -12.2, 44.6, 12.7);
$positive = array();
$negative = array();
foreach($numbers as $n) {
if($n > 0):
$positive[] = intval($n);
else:
$negative[] = intval($n);
endif;
}
?>
Is there a way to write this with less code like you can do in Python?
You can use array_filter and anonymous functions (the latter only if you have PHP 5.3 or higher), but the way that you showed with more code is more efficient and looks neater to me.
$positive = array_filter($numbers, function($x) { return $x > 0; });
$negative = array_filter($numbers, function($x) { return $x < 0; });
And array_map to apply intval:
$positive = array_map('intval', array_filter($numbers, function($x) { return $x > 0; }));
$negative = array_map('intval', array_filter($numbers, function($x) { return $x < 0; }));
Sure. Use array_filter
$positive = array_filter($numbers,function($a) {return $a > 0;});
$negative = array_filter($numbers,function($a) {return $a < 0;});
PHP is a bit more verbose in the array / map handling, it's one of Python's strengths. There are some functions that can help with dealing with arrays, like for instance:
$positive = array_filter($numbers,function($n){return $n > 0;});
$positive = array_map('intval',$positive);
$negative = array_filter($numbers,function($n){return $n < 0;});
$negative = array_map('intval',$positive);
No... As far as I am aware, foreach loop is the only way to go.
And this is not that much more of code.
But if you want to make it a little shorter, you can get rid of explicit array declarations just before the foreach loop.
Related
Example:
$a[] = '56';
$a[] = '66';
$a[] = '';
$a[] = '58';
$a[] = '85';
$a[] = '';
$a[] = '';
$a[] = '76';
$a[] = '';
$a[] = '57';
Actually how to find average value from this array excluding empty. please help to resolve this problem.
first you need to remove empty values, otherwise average will be not accurate.
so
$a = array_filter($a);
$average = array_sum($a)/count($a);
echo $average;
DEMO
More concise and recommended way
$a = array_filter($a);
if(count($a)) {
echo $average = array_sum($a)/count($a);
}
See here
The accepted answer works for the example values, but in general simply using array_filter($a) is probably not a good idea, because it will filter out any actual zero values as well as zero length strings.
Even '0' evaluates to false, so you should use a filter that explicitly excludes zero length strings.
$a = array_filter($a, function($x) { return $x !== ''; });
$average = array_sum($a) / count($a);
echo array_sum($a) / count(array_filter($a));
As a late look, item controls should be done with numeric check. Otherwise something like this $array = [1.2, 0.33, [123]] will corrupt the calculation:
// Get numerics only.
$array = array_filter($array, fn($v) => is_numeric($v));
// Get numerics only where value > 0.
$array = array_filter($array, fn($v) => is_numeric($v) && ($v > 0));
Finally:
public static function average(array $array, bool $includeEmpties = true): float
{
$array = array_filter($array, fn($v) => (
$includeEmpties ? is_numeric($v) : is_numeric($v) && ($v > 0)
));
return array_sum($array) / count($array);
}
Credits: froq.util.Arrays
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;
}
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;
}
I want to tell my array to start from key position 2 and then loop through the entire array, including the values before key position 2. I just want to use one array and specify the key position I start looping from. For example, here I am using array_splice, but it does not do what I want it to, could you help me please?
$names = array('Bill', 'Ben', 'Bert', 'Ernie');
foreach(array_slice($names, 2) as $name){
echo $name;
}
foreach(array_slice($names, 3) as $name){
echo $name;
}
If the keys are irrelevant, you can splice the array twice, and merge the resulting arrays, like this:
$names = array('Bill', 'Ben', 'Bert', 'Ernie');
$start = 2;
foreach( array_merge( array_slice($names, $start), array_slice( $names, 0, $start)) as $name){
echo $name;
}
You can see from the demo that this prints:
BertErnieBillBen
Alternatively, for efficiency, you can use two loops that are aware of wrapping around to the beginning, which will be more efficient since you are operating on the original array and not creating copies of it.
$start = 2;
for( $i = $start, $count = count( $names); $i < $count; $i++) {
echo $names[$i];
}
$i = 0;
while( $i < $start) {
echo $names[$i++];
}
You could also turn this into one single loop, and just encapsulate the logic for wrapping around inside the for.
$limit = 2; //so you can set your start index to an arbitrary number
$fn= function($a,$b) use ($limit){
if(($a < $limit && $b < $limit)
|| ($a >= $limit && $b >=$limit)) //$a and $b on the same side of $limit
return $a < $b ? -1 : ($a==$b ? 0 : 1);
if($a < $limit && $b > $limit) return 1; //because $a will always be considered greater
if($a >= $limit && $b < $limit) return -1; //because $b will always be considered greater
};
uksort($arr, $fn);
foreach($arr as $v) echo $v;
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;
});