PHP array_filter with arguments - php

I have the following code:
function lower_than_10($i) {
return ($i < 10);
}
that I can use to filter an array like this:
$arr = array(7, 8, 9, 10, 11, 12, 13);
$new_arr = array_filter($arr, 'lower_than_10');
How can I add arguments to lower_than_10 so that it also accepts the number to check against? Like, if I have this:
function lower_than($i, $num) {
return ($i < $num);
}
how to call it from array_filter passing 10 to $num or whatever number?

if you are using php 5.3 and above, you can use closure to simplify your code:
$NUM = 5;
$items = array(1, 4, 5, 8, 0, 6);
$filteredItems = array_filter($items, function($elem) use($NUM){
return $elem < $NUM;
});

As an alternative to #Charles's solution using closures, you can actually find an example in the comments on the documentation page. The idea is that you create an object with the desired state ($num) and the callback method (taking $i as an argument):
class LowerThanFilter {
private $num;
function __construct($num) {
$this->num = $num;
}
function isLower($i) {
return $i < $this->num;
}
}
Usage (demo):
$arr = array(7, 8, 9, 10, 11, 12, 13);
$matches = array_filter($arr, array(new LowerThanFilter(12), 'isLower'));
print_r($matches);
As a sidenote, you can now replace LowerThanFilter with a more generic NumericComparisonFilter with methods like isLower, isGreater, isEqual etc. Just a thought — and a demo...

In PHP 5.3 or better, you can use a closure:
function create_lower_than($number = 10) {
// The "use" here binds $number to the function at declare time.
// This means that whenever $number appears inside the anonymous
// function, it will have the value it had when the anonymous
// function was declared.
return function($test) use($number) { return $test < $number; };
}
// We created this with a ten by default. Let's test.
$lt_10 = create_lower_than();
var_dump($lt_10(9)); // True
var_dump($lt_10(10)); // False
var_dump($lt_10(11)); // False
// Let's try a specific value.
$lt_15 = create_lower_than(15);
var_dump($lt_15(13)); // True
var_dump($lt_15(14)); // True
var_dump($lt_15(15)); // False
var_dump($lt_15(16)); // False
// The creation of the less-than-15 hasn't disrupted our less-than-10:
var_dump($lt_10(9)); // Still true
var_dump($lt_10(10)); // Still false
var_dump($lt_10(11)); // Still false
// We can simply pass the anonymous function anywhere that a
// 'callback' PHP type is expected, such as in array_filter:
$arr = array(7, 8, 9, 10, 11, 12, 13);
$new_arr = array_filter($arr, $lt_10);
print_r($new_arr);

if you need multiple parameters to be passed to the function, you may append them to the use statement using ",":
$r = array_filter($anArray, function($anElement) use ($a, $b, $c){
//function body where you may use $anElement, $a, $b and $c
});

In extension to jensgram answer you can add some more magic by using the __invoke() magic method.
class LowerThanFilter {
private $num;
public function __construct($num) {
$this->num = $num;
}
public function isLower($i) {
return $i < $this->num;
}
function __invoke($i) {
return $this->isLower($i);
}
}
This will allow you to do
$arr = array(7, 8, 9, 10, 11, 12, 13);
$matches = array_filter($arr, new LowerThanFilter(12));
print_r($matches);

Worth noting that since PHP 7.4 arrow functions are available, and this can be done even more neatly:
$max = 10;
$arr = array(7, 8, 9, 10, 11, 12, 13);
$new_arr = array_filter($arr, fn ($n) => $n < $max);

class ArraySearcher{
const OPERATOR_EQUALS = '==';
const OPERATOR_GREATERTHAN = '>';
const OPERATOR_LOWERTHAN = '<';
const OPERATOR_NOT = '!=';
private $_field;
private $_operation;
private $_val;
public function __construct($field,$operation,$num) {
$this->_field = $field;
$this->_operation = $operation;
$this->_val = $num;
}
function __invoke($i) {
switch($this->_operation){
case '==':
return $i[$this->_field] == $this->_val;
break;
case '>':
return $i[$this->_field] > $this->_val;
break;
case '<':
return $i[$this->_field] < $this->_val;
break;
case '!=':
return $i[$this->_field] != $this->_val;
break;
}
}
}
This allows you to filter items in multidimensional arrays:
$users = array();
$users[] = array('email' => 'user1#email.com','name' => 'Robert');
$users[] = array('email' => 'user2#email.com','name' => 'Carl');
$users[] = array('email' => 'user3#email.com','name' => 'Robert');
//Print all users called 'Robert'
print_r( array_filter($users, new ArraySearcher('name',ArraySearcher::OPERATOR_EQUALS,'Robert')) );

Related

How to sum array using function in PHP

I got exercise to do.
Need to create a function called sumArray() that should take an array as argument and return the sum of all items in the array. Answer with a call to the function using the array: [4,256,5,13,1].Write your code below and put the answer into the variable ANSWER.
So long I came but it doesn't work.
function sumArray($array) {
$total = 0;
foreach ($array as $value) {
$total += $value;
}
return $array;
}
$ANSWER = sumArray(4, 256, 5, 13, 1);
So close. Just 2 things to do.
function sumArray($array) {
$total = 0;
foreach ($array as $value) {
$total += $value;
}
//YOU NEED TO RETURN $total !! not $array
return $total;
}
//the params given to sumArray() are not an array. just encapsule that in [] like:
$ANSWER = sumArray([4, 256, 5, 13, 1]);
First of all you need to return $total, you are again returning your array.
Second, you must need to pass array in function argument as:
$sumArray = array(4, 256, 5, 13, 1); // your array
$myAnswer = sumArray($sumArray); // calling function
Example:
<?php
function sumArray($array) {
$total = 0;
foreach ($array as $value) {
$total += $value;
}
return $total;
}
/** Your array **/
$sumArray = array(4, 256, 5, 13, 1);
/** Calling function **/
$myAnswer = sumArray($sumArray);
/** Your result **/
echo $myAnswer; //279 result
?>
You can just use PHP's built in array_sum method.
http://php.net/manual/en/function.array-sum.php
$ANSWER = array_sum(array(4, 256, 5, 13, 1));
If you must create a function then wrap it.
function sumArray($array) {
return array_sum($array);
}
$ANSWER = sumArray(array(4, 256, 5, 13, 1));
Note. In your example you haven't provided an array you have various arguments. You could also do that like so:
function sumArray() {
return array_sum(func_get_args());
}
$ANSWER = sumArray(4, 256, 5, 13, 1);
Edit. As this answer got down voted for not providing an example on how to add it up here it is. Though you should always use the built in function if it's a available and teaching you to avoid it is counterintuitive.
function sumArray($array) {
for($i = 0, $total = 0; $i < count($array); $total+=$array[$i++]);
return $total;
}
$ANSWER = sumArray([4, 256, 5, 13, 1]);
Since you need to write a function, your code should look like this:
function sumArray($array) {
$total = 0;
foreach ($array as $value) {
$total += $value;
}
return $total;
}
$ANSWER = sumArray(array(4, 256, 5, 13, 1));
Your code isn't working because you're not passing an array to the function, and you're also returning the parameter and not the $total variable.
Alternatively, you can use array_sum inside a function of your own.

Can someone provide the general function to shift the items from array based on given offset?

I would like to shift the items in array based on given offset. In my current project I need to do this often so I am looking for a common function.
$data = [1, 2, 3, 4, 5, 6];
$data = shift($data, 2);
dd($data); //should result into [3, 4, 5, 6, 1, 2]
function shift($data, $offset) {
// general code
}
Thanks in advance.
Surely as simply as shifting and pushing in a loop
function shift($data, $offset) {
do {
$data[] = array_shift($data);
} while (--$offset > 0);
return $data;
}
EDIT
If you need to work with negative offsets as well,
function shift($data, $offset) {
if ($offset > 0) {
do {
$data[] = array_shift($data);
} while (--$offset > 0);
} elseif ($offset < 0) {
do {
array_unshift($data, array_pop($data));
} while (++$offset < 0);
}
return $data;
}
You can use laravel collection macro to create your own custom functions.
Below is the macro which will support the negative offset as well.
$collection = collect([1, 2, 3, 4, 5, 6]);
$rotate = $collection->rotate(2);
$rotate->toArray();
// [3, 4, 5, 6, 1, 2]
Collection::macro('rotate', function ($offset) {
if ($this->isEmpty()) {
return new static;
}
$count = $this->count();
$offset %= $count;
if ($offset < 0) {
$offset += $count;
}
return new static($this->slice($offset)->merge($this->take($offset)));
});
You can use collection in native PHP as well but below function can be used in native PHP.
function array_rotate($array, $shift) {
$shift %= count($array);
if($shift < 0) $shift += count($array);
return array_merge(array_slice($array, $shift, NULL, true), array_slice($array, 0, $shift, true));
}
Both functions will preserve keys if explicitly specified.

Is there a PHP function that will check to make sure fields are set in an array

Does php library have any function to check if all required fields are set in an array? For example:
function required_fields($vals,$required_fields_names){
for($i = 0; $i < count($required_fields_names); $i++){
if(!array_key_exists($required_fields_names[$i],$vals)){
return false
}
}
return true;
}
Is there already a native PHP function/method that does this?
array_difference is the closest built-in function for this:
function required_fields($vals,$required_fields_names){
$missing_fields = array_difference($required_fields_names, array_keys($vals));
return empty($missing_fields);
}
NO, there is no native method.
But you can improve that code.
<?php
function check_keys($keys,$array) {
foreach ($keys as $key) {
if(!array_key_exists($key, $array)) {
return false;
}
}
return true;
}
# Test Zone
$a = array('a' => 1,
'b' => 2,
'c' => 3);
$b = ['a','b','c'];
$c = ['a','b'];
$d = ['a','b','d'];
echo (int) check_keys($b,$a).'</br>'; # 1
echo (int) check_keys($c,$a).'</br>'; # 1
echo (int) check_keys($d,$a).'</br>'; # 0
?>

PHP Function 'return' not returning value

I have a algorithm to find all unique combinations of an array of foods. If any of combinations match our calories value then it should return true.
Here is my approach:
<?php
$food = [
['a', 70],
['b', 5],
['c', 20],
['d', 10]
];
function eat($calories, $food, $k = 0, $p = []) {
for ($i=$k; $i < count($food); $i++) {
$r = array_merge($p, [$i]);
$c = 0;
foreach ($r as $j) {
$c += $food[$j][1];
}
if ($c == $calories) {
echo "success";
return true;
}
eat($calories, $food, $i+1, $r);
}
}
var_dump(eat(100, $food));
?>
The question is: Why this code output 'success' but doesn't return true?
Here is the online execution:
http://codepad.viper-7.com/PnTEKo
The original function you call never returns true, the subsequent funtion that is called returns true to its "parent", but that true is never returned to the original caller. A fix would be as follows:
if (eat($calories, $food, $i+1, $r)) {
return true;
}
This checks what the recursive function returns, and if its true, returns true again
A slightly different take on the recursive array function would be to use the built in function arrayIterator.
$food = array(
'a'=> 70,
'b'=> 5,
'c'=> 20,
'd'=> 10,
'e'=> 99
);
function eat( $calories, $food, $p=array() ){
$a = new ArrayObject( array_merge( $food, $p ) );
$iterator = $a->getIterator();
while( $iterator->valid() ) {
if( $iterator->current()==$calories ) {
echo 'success: key='.$iterator->key().' value='.$iterator->current();
return true;
}
$iterator->next();
}
return false;
}
eat( 120, $food, array( 'banana'=>500,'apple'=>120 ) );
You are calling the function recursively. The dumped value will be the returned value of the first call, because you ignore the returned values of other calls.
Here, it seems that you only need to reach one successful call, and after that the function must be terminated. So you can check for the success, and if it has happened, return true, to prevent the function going further, and tell the caller(this can be the first call, or any other calls in recursion) that the call was successful.
<?php
$food = [
['a', 70],
['b', 5],
['c', 20],
['d', 10]
];
function eat($calories, $food, $k = 0, $p = []) {
for ($i=$k; $i < count($food); $i++) {
$r = array_merge($p, [$i]);
$c = 0;
foreach ($r as $j) {
$c += $food[$j][1];
}
if ($c == $calories) {
echo "success";
return true;
}
if(eat($calories, $food, $i+1, $r))
return true;
}
}
var_dump(eat(100, $food));
?>

recursively add elements to array and return new array

Let's say I have an array like this:
$my_array = array(1, 2, 3, 4, array(11, 12, 13, 14), 6, 7, 8, array(15, 16, 17, 18), 10);
I want to build a recursive function that returns an array which contains all the even numbers from my_array. I tried something like:
function get_even_numbers($my_array)
{
$even_numbers = array();
foreach($my_array as $my_arr)
{
if(is_array($my_arr)
{
get_even_numbers($my_arr);
foreach($my_arr as $value)
{
if($value % 2 == 0)
{
$even_numbers[] = $value;
}
}
}
}
return even_numbers;
}
But it doesn't works.
Thank you
It's simple:
Check if the input you get into the function is an array.
If it is, that means you have to loop over the values of the array, and call your function (so it is recursive)
Otherwise, just check if the value coming in is even, and add it to an array to return.
That, in PHP, looks like:
function recursive_even( $input) {
$even = array();
if( is_array( $input)) {
foreach( $input as $el) {
$even = array_merge( $even, recursive_even( $el));
}
}
else if( $input % 2 === 0){
$even[] = $input;
}
return $even;
}
Unless it is a thought exercise for your own edification, implementing a recursive function isn't required for this task, which can accomplished instead by using the higher-order, built-in PHP function, array_walk_recursive.
$res = array();
array_walk_recursive($my_array, function($a) use (&$res) { if ($a % 2 == 0) { $res[] = $a; } });
Of course, this could be wrapped in a function:
function get_even_numbers($my_array) {
$res = array();
array_walk_recursive($my_array, function($a) use (&$res) { if ($a % 2 == 0) { $res[] = $a; } });
return $res;
}

Categories