Return one dimensional array instead of multi - php

Ok so I'm wanting just the years returned as a one dimensional array instead of a multi when pulling from the database:
public function getYears($make = null, $model = null) {
// select table
$this->select(array('DISTINCT year'));
$this->table($this->table);
// build where clause
if( $make !== null && $model !== null ) {
$this->where('make', '=', $make);
$this->and_where('model', '=', $model);
} elseif( $make !== null && $model === null ) {
$this->where('make', '=', $make);
} elseif( $make === null && $model !== null ) {
$this->where('model', '=', $model);
}
return $this->all();
}
This function basically just returns SELECT DISTINCT year FROM vehicle;
In another script, I'm doing:
$years = $vehicle->getYears();
However it returns as so:
array (size=1)
0 =>
array (size=1)
'year' => string '2014' (length=4)
1 =>
array (size=1)
'year' => string '2013' (length=4)
I want it to just return as so:
array (size=1)
0 => string '2014' (length=4)
1 => string '2013' (length=4)
Is that possible? Because I'm putting it through my select form helper function that takes a one dimensional array of all your options and loops through them. But it can't loop through a multi-list because it's trying to echo out the index which is unfortunately an array.. not a string.
Thanks for any help.

Just an example, needs error checking / check for valid column, etc...
public function all($column=null) {
$this->execute();
if($column === null) {
return $this->stmt->fetchAll(PDO::FETCH_ASSOC);
}
while($row = $this->stmt->fetch(PDO::FETCH_ASSOC)) {
$result[] = $row[$column];
}
return $result;
}
Or create another method all_single($column) or something and use that instead. No need to loop through the results of all(). The only time you'll need this is if you only get a single column.
Also you can restructure this based on whether you like to return once or return early as shown.

You either edit your All method, create a new method such as AllOneDimentional (not a great name!) or you take the data returned from All and manipulate it:
foreach($years as $year)
$onedimyears[]=$year['year'];

In the past when i've attempted this i've used this function
function flatten(array $array) {
$return = array();
array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
return $return;
}
It's as about as efficient as you can get assuming your on php 5.3 or greater

Related

How to return an element of array, which finded by recursion?

So, i have a little trouble:
I have a class, let's name it "Menu", also, i have an array, which provides an elements for "Menu", it looks like that
class Menu {
private $_data = [];
public function __construct() {
$this->_data = array(
"Parent1" => array(
"Child1" => array(
"id" => 1,
"minQuantity" => x,
"maxQuantity" => x,
"cost" => x,
),
"Child2"...
),
"ParentX" => array(
"ChildXX"...
)
/* AND SO ON */
);
}
}
Also, in "Menu" i have a function, which by recursion try to find an element of the $this->_data with specified value, function looks like that:
public function findChildById($parent = null, $id = null) {
foreach ($parent as $_parent => $_child) {
if (array_key_exists($id, $parent)) var_dump($parent);
if (is_array($_child)) $this->findChildById($_child, $id);
}
}
But, when it finds needed element, and I try to return it - result is always NULL. Using var_dump leads to obvious output, I can see what exactly what I need, but i cant return an element from function. What should i do?
Since you only try to find one element, it should be enough to pass the return value up the recursion stack. E.g. like this:
public function findChildById($parent = null, $id = null) {
foreach ($parent as $_parent => $_child) {
if (array_key_exists($id, $parent)) return $parent; //first return
if (is_array($_child)) {
$tmp = $this->findChildById($_child, $id);
if (!is_null($tmp)) return $tmp; //if a deeper step found sth. pass it up
}
}
}
The reason for the NULLs you get, must be, because PHP functions return NULL implicitly when the code does not reach a return statement.

return boolean if any item in the array is empty/not empty

I have an array of objects. I need to loop over these objects (preferably without foreach(), and if a certain key in the objects is not empty, then return true, otherwise return false.
For example,
$items = array(
'0' => stdClass {
name => Ryan
suppliers => array()
}
'1' => stdClass {
name => Dave
suppliers => array(
'0' => stdClass {}
)
}
)
Essentially, I need to go through the array and check the "supplier" key of the object, and if any of them are not empty, return true for the entire thing, otherwise return false.
What's wrong with foreach?
$check = function($arr) {
foreach($arr as $o) {
if (!empty($o->suppliers)) return true;
}
return false;
};
If you want to use it only in one place, use anonymous function
I don't understand why you don't want to use foreach because thing is - foreach is only right way because you leave loop as soon as you find value
One other option, reduce the array to a boolean.
array_reduce($items, function($hasSupplier, $item) {
return !empty($item->suppliers) || $hasSupplier;
});
Still, I prefer the foreach solution since it won't continue to iterate unnecessarily.
You can filter and check for a result:
if(array_filter($items, function($v) { return !empty($v->suppliers); })) {
//at least one not empty
} else {
//all are empty
}
If you really want a boolean:
$result = (bool)array_filter($items, function($v) { return !empty($v->suppliers); })

How do I return literal values of a PHP string so it runs as code?

I am not sure I am using the right terms even here, but I will try and explain. I am using PHP's array_filter function to filter products and it calls back to a custom function I made where I add the filter(s). I can do this hard-coded very easy, but I obviously want it to be dynamic:
To cut a long story short, the custom filter function returns to the array_filter() function like so:
return ($arr['colour']=='Red' || $arr['colour']=='White');
This works fine if hardcoded like the above, and filters the array as expected to only show products that are red or white. However, I need this to be dynamic.
So how can I construct a string of values and then use this in the return statement?
For example:
$var = "$arr['colour'] == 'Red' || $arr['colour'] == 'White'";
return ($var);
It does not work. I have tried using eval() (I don't want to use this anyway!), and it didn't work still.
I have a loop as follows constructing the string from an array:
// $value=array of filters e.g colour=Black, colour=Red
$filterparts = explode("=", $value);
$filters[] = '$arr[\'' . $filterparts[0] . '\'] == \'' . $filterparts[1] . '\'';
// Creates array e.g $arr['colour'] = 'Red'
$imploded_filter = implode(" || ", $uniquefilters);
// Creates string, e.g. $arr['colour'] = 'Red' || $arr['colour'] = 'White'
So if I echo $imploded_filter I get the extract string I would like to return:
echo $imploded_filter;
// Outputs $arr['colour'] = 'Red' || $arr['colour'] = 'White'
However if I do
return($imploded_filter);
it obviously isn't evaluating the string as hard code, so what can I do? Do I need to do something to the string or return it a different way, or construct the code I need to return in a totally different way?
Array keys can be specified dynamically. There isn't any need for eval():
$value = $array[$key];
You can build a list of filters and match each of them in the array_filter() callback:
$filters = array(
array('colour', array('white', 'blue')), // Multiple accepted values (OR)
array('material', 'Fine Bone China'), // Single accepted value
);
$filtered = array_filter($products, function ($item) use ($filters) {
// Match all filters
foreach ($filters as $filter) {
// Detect multi-value filter
$isArrayFilter = is_array($filter[1]);
if (
// Check if multi-value filter doesn't match
$isArrayFilter && !in_array($item[$filter[0]], $filter[1])
// Check if a single-value filter doesn't match
|| !$isArrayFilter && $item[$filter[0]] != $filter[1]
) {
// Filter doesn't match - exclude the item
return false;
}
}
// All filters match - include the item
return true;
});
$colors = ['Red', 'White'];
$products = array_filter($products, function ($product) use ($colors) {
return in_array($product['color'], $colors);
});
There's virtually never any reason or need to "dynamically create PHP source code". There's always an operation that can do what you want on any number of elements without needing to concatenate || operators. Here in_array is a perfectly fine function to test one value against many. You can pass in the colors array dynamically using use ($colors).
The sanest workaround for ancient PHP versions is to approximate the anonymous callback with a class:
class InArrayFilterCallback {
public $data = array();
public $key;
public __construct($data, $key) {
$this->data = $data;
$this->key = $key;
}
public callback($item) {
return in_array($item[$this->key], $this->data);
}
}
$products = array_filter($products, array(new InArrayFilterCallback($colors, 'color'), 'callback'));
Of course, you could also just use a simple foreach loop instead...
Use the in_array function, like so:
$filters = [
'colour' => [
'red',
'blue',
]
];
array_filter($list, function ($item) use ($filters) {
foreach ($filters as $index => $filter) {
if (!in_array($item[$index], $filter)) {
return false;
}
}
return true;
});
It is never a good idea to make a string and eval'uate it.

How to get values that doesn't pass from FilterIterator

I'm using FilterIterator to filter out the values and implemented the accept() method successfully. However I was wondering how would it be possible to get the values that returned false from my accept method in single iteration. Let's take the code below as an example (taken from php.net);
class UserFilter extends FilterIterator
{
private $userFilter;
public function __construct(Iterator $iterator , $filter )
{
parent::__construct($iterator);
$this->userFilter = $filter;
}
public function accept()
{
$user = $this->getInnerIterator()->current();
if( strcasecmp($user['name'],$this->userFilter) == 0) {
return false;
}
return true;
}
}
On the code above, it directly filters out the values and returns the values that pass from the filteriterator. Implemented as;
$array = array(
array('name' => 'Jonathan','id' => '5'),
array('name' => 'Abdul' ,'id' => '22')
);
$object = new ArrayObject($array);
$iterator = new UserFilter($object->getIterator(),'abdul');
It will contain only the array with name Jonathan. However I was wondering would it be possible to store the object with name Abdul in another variable using the same filter with a slight addition instead of reimplementing the entire filter to do the opposite?. One way I was thinking would exactly copy paste the FilterIterator and basically change values of true and false. However are there any neat ways of doing it, since it will require another traversal on the list.
I think you must rewrite the accept() mechanic. Instead of returning true or false, you may want to break down the array to
$result = array(
'passed' => array(...),
'not_passed' => array(...)
);
Your code may look like this
if (strcasecmp($user['name'], $this->userFilter) == 0) {
$result['not_passed'][] = $user;
} else {
$result['passed'][] = $user;
}
return $result;

Property is null in method 2 after being set in method 1

hoping you can help me out with this question!
Index.php
include_once 'files.class.php';
$file_object = new FileObject('resources');
$file_object->ReturnCurrentDirectoryList();
files.class.php
class FileObject{
public $directory_list;
function __construct($current_directory_in){
$this->directory_list = $this->BuildCurrentDirectoryList($current_directory_in);
}
function BuildCurrentDirectoryList($current_directory_in){
$i = 0;
$iterator = new DirectoryIterator($current_directory_in);
foreach ($iterator as $fileinfo){
if ($fileinfo->isDir()){
$this->directory_list[$i]['pathname'] = $fileinfo->getPathname();
}elseif($fileinfo->isFile()){
$this->directory_list[$i]['filename'] = $fileinfo->getFilename();
}
$i++;
}
}
function ReturnCurrentDirectoryList(){
var_dump($this->directory_list);
}
}
At the end of all this, what is returned is
null
but what should be returned is
array 0 => array 'pathname' => string 'resources\.', 1 => array 'pathname' => string 'resources\..', 2 => array 'pathname' => string 'resources\Images'
I'm somewhat new to classes/methods..
This is wrong:
$this->directory_list = $this->BuildCurrentDirectoryList($current_directory_in);
You assign to $this->directory_list but BuildCurrentDirectoryList does not return anything. The function have side-effects only, no return value.
Remove the assignment so the constructor looks like this and you should be good to go:
$this->directory_list = array(); //I like to initialise arrays to the empty array
$this->BuildCurrentDirectoryList($current_directory_in);
In your constructor, you are assigning directory_list to the return of BuildCurrentDirectoryList, but you are not returning nothing in BuildCurrentDirectoryList, you are assigning directory_list directly in that method. At the end, BuildCurrentDirectoryList returns NULL. So, either return the directory_list, or else just don't assign it like this:
function __construct($current_directory_in){
$this->BuildCurrentDirectoryList($current_directory_in);
}

Categories