Array Mapping function, returns false every time - php

Ok, trying to make a function that I can pass a variable to, that will search a static currently hardcoded multi dimensional array for its keys, and return the array matched to the key found (if found).
This is what I have thus far.
public function teamTypeMapping($teamType)
{
//we send the keyword football, baseball, other, then we return the array associated with it.
//eg: we send football to this function, it returns an array with nfl, college-football
$mappings = array(
"football" => array('nfl', 'college-football'),
"baseball" => array('mlb', 'college-baseball'),
"basketball" => array('nba', 'college-basketball'),
"hockey" => array('nhl', 'college-hockey'),
);
foreach($mappings as $mapped => $item)
{
if(in_array($teamType, $item)){return $mapped;}
}
return false;
}
And I'd like to make a call to it, example:
teamTypeMapping("football");
Amd have it return the array associated with the key "football", I have tried this a couple ways, and each time I come up false, maybe I am missing something so Im up for taking some advice at this point.

The reason it's not working is that you are looping through the $mappings array, and trying to see if $teamType is in the $item.
There are two problems with your approach:
You are looking in the $item (this is the array('nfl', 'college-football')) for 'football'. This is incorrect.
You are using in_array() which checks if a 'value' is in the array, not the 'key' that you have used. You might want to take a look at the array_key_exists() function - I think this is what you meant to use.
My personal preference is to use isset() instead of array_key_exists(). Slightly different syntax, but both do the same job.
See below for a revised solution:
public function teamTypeMapping($teamType)
{
//we send the keyword football, baseball, other, then we return the array associated with it.
//eg: we send football to this function, it returns an array with nfl, college-football
$mappings = array(
"football" => array('nfl', 'college-football'),
"baseball" => array('mlb', 'college-baseball'),
"basketball" => array('nba', 'college-basketball'),
"hockey" => array('nhl', 'college-hockey'),
);
if (isset($mappings[$teamType]))
{
return $mappings[$teamType];
}
return false;
}

I checked your function
public function teamTypeMapping($teamType)
{
//we send the keyword football, baseball, other, then we return the array associated with it.
//eg: we send football to this function, it returns an array with nfl, college-football
$mappings = array(
"football" => array('nfl', 'college-football'),
"baseball" => array('mlb', 'college-baseball'),
"basketball" => array('nba', 'college-basketball'),
"hockey" => array('nhl', 'college-hockey'),
);
foreach($mappings as $mapped => $item)
{
if(in_array($teamType, $item)){return $mapped;}
}
return false;
}
And when you like to make a call to it, example:
teamTypeMapping("football");
then it return false.
Solution is If your want the array then you want
foreach($mappings as $mapped => $item)
{
if($mapped == $teamType){return $mapped;}
}

Related

Modifying an array sub-value that has been returned by a function

I needed a function that recursively parses a multi-dimensional array for a (part) of a certain string value and, if found, returns the entire value the string is contained in.
I came up with the following solution:
function & ransackArray(array & $haystack, $needle) {
foreach($haystack as &$element) {
if(is_array($element)){
if($v=ransackArray($element, $needle))
return $v;
} else {
if(strstr($element, $needle))
return $element;
}
}
return false;
}
This works fine. For instance, providing:
$data=array(
'key' => 'something',
'children' => array(
'someValue' => 'myTest',
'someMore' => 'yes'
)
);
And running:
$r=ransackArray($data, 'myTes');
This will result in $r containing 'myTest'.
The problem is that now that i found this value, i want to change it in $data, right on the fly, by writing:
$r='new value';
Which should then effectively result in data looking like this:
$data=array(
'key' => 'something',
'children' => array(
'someValue' => 'new value',
'someMore' => 'yes'
)
);
This however, doesn't seem to work. Perhaps i misunderstand something about references. In any case, the reason i needed this to work is why i pass $haystack as a reference and also return the function's result as one.
Can this be done? If yes, how? And if not - why not?
You're missing two ampersands...one on this line:
if($v = self::ransackArray($element, $needle))
which should be:
if($v = &self::ransackArray($element, $needle))
and one on this line:
$r = ransackArray($data, 'myTes');
which should be:
$r = &ransackArray($data, 'myTes');
(Note: it looks like your ransackArray function is actually a method in a class, so if you're calling that method from within the class it would be $r = &$this->ransackArray($data, 'myTes');)
When passing variables to a function, you don't need to use & - just put the & in front of the parameter in the function signature - but in cases like yours where you are getting a return value from a function, there needs to be a & both in the function call and in the function signature. For more info see http://www.php.net/manual/en/language.references.pass.php

Sorting multi-dimensional array by weighted value

There are numerous questions here asking how to sort a multi-dimensional array in PHP. The answer is usort(). I know that. But I have a question that takes it a bit further, and I couldn't see a similar answer here.
I have an array of records, each of which includes a country ID (or a country name if you prefer; it's not relevant).
My task is to sort the array in such a way as to favour certain countries. This is dynamic -- ie the choice of countries to favour is determined by the user's config. I have a separate array which specifies the required sort order for the first few countries; results from other countries would just be left unsorted at the end of the list.
So the question is: how do I get the this sort criteria into usort() without resorting to using a global variable. And preferably without injecting the criteria array into every element of the main array ('coz if I'm going to loop it anyway, what's the point in using usort() at all?)
Please note: Since it's going to be relevant to the answers here, I'm stuck on PHP 5.2 for the time being, so I can't use an anonymous function. We are in the process of upgrading, but for now I need answers that will work for 5.2. (answers for 5.3/5.4 will be welcome too, especially if they make it significantly easier, but I won't be able to use them)
You explicitly write that you do not want to have global variables, so I do not make you a suggestion with static variables as well because those are actually global variables - and those are not needed at all.
In PHP 5.2 (and earlier) if you need call context within the callback, you can create your context by making use of a class of it's own that carries it:
class CallContext
{
}
For example you have the compare function for sort:
class CallContext
{
...
public function compare($a, $b)
{
return $this->weight($a) - $this->weight($b);
}
public function getCallback()
{
return array($this, 'compare');
}
...
}
That function can be used as the following as a callback with usort then:
$context = new CallContext();
usort($array, $context->getCallback());
Pretty straight forward. The private implementation of CallContext::weight is still missing, and from your question we know it needs some sort data and information. For example the name of the key of the country id in each record. Lets assume records are Stdclass objects so to get the weight of one record the context class needs to know the name of the property, the sort-order you define your own and a sort-value for those country-ids that are not defined in the custom sort order (the others, the rest).
These configuration values are given with the constructor function (ctor in short) and are stored as private members. The missing weight function then converts a record into the sort-value based on that information:
class CallContext
{
private $property, $sortOrder, $sortOther;
public function __construct($property, $sortOrder, $sortOther = 9999)
{
$this->property = $property;
$this->sortOrder = $sortOrder;
$this->sortOther = $sortOther;
}
private function weight($object) {
if (!is_object($object)) {
throw new InvalidArgumentException(sprintf('Not an object: %s.', print_r($object, 1)));
}
if (!isset($object->{$this->property})) {
throw new InvalidArgumentException(sprintf('Property "%s" not found in object: %s.', $this->property, print_r($object, 1)));
}
$value = $object->{$this->property};
return isset($this->sortOrder[$value])
? $this->sortOrder[$value]
: $this->sortOther;
}
...
The usage now extends to the following:
$property = 'country';
$order = array(
# country ID => sort key (lower is first)
46 => 1,
45 => 2
);
$context = new CallContext('country', $order);
usort($array, $context->getCallback());
With the same principle you can very often convert any PHP 5.3 closure with use clauses to PHP 5.2. The variables from the use clause become private members injected with construction.
This variant does not only prevent the usage of static, it also makes visible that you have got some mapping per each element and as both elements are treated equal, it makes use of a private implementation of some weight function which works very well with usort.
I hope this is helpful.
You might not want a global variable, but you need something that behaves like one. You could use a class with static methods and parameters. It won't pollute the global scope that much and it would still function the way you need it.
class CountryCompare {
public static $country_priorities;
public static function compare( $a, $b ) {
// Some custom sorting criteria
// Work with self::country_priorities
}
public static function sort( $countries ) {
return usort( $countries, array( 'CountryCompare', 'compare' ) );
}
}
Then just call it like this:
CountryCompare::country_priorities = loadFromConfig();
CountryCompare::sort( $countries );
You can use closures (PHP >= 5.3):
$weights = array( ... );
usort($records, function($a, $b) use ($weights) {
// use $weights in here as usual and perform your sort logic
});
See Demo : http://codepad.org/vDI2k4n6
$arrayMonths = array(
'jan' => array(1, 8, 5,4),
'feb' => array(10,12,15,11),
'mar' => array(12, 7, 4, 3),
'apr' => array(10,16,7,17),
);
$position = array("Foo1","Foo2","Foo3","FooN");
$set = array();
foreach($arrayMonths as $key => $value)
{
$max = max($value);
$pos = array_search($max, $value);
$set[$key][$position[$pos]] = $max ;
}
function cmp($a, $b)
{
foreach($a as $key => $value )
{
foreach ($b as $bKey => $bValue)
{
return $bValue - $value ;
}
}
}
uasort($set,"cmp");
var_dump($set);
output
array
'apr' =>
array
'FooN' => int 17
'feb' =>
array
'Foo3' => int 15
'mar' =>
array
'Foo1' => int 12
'jan' =>
array
'Foo2' => int 8
another example:-
Sorting a Multi-Dimensional Array with PHP
http://www.firsttube.com/read/sorting-a-multi-dimensional-array-with-php/
Every so often I find myself with a multidimensional array that I want to sort by a value in a sub-array. I have an array that might look like this:
//an array of some songs I like
$songs = array(
'1' => array('artist'=>'The Smashing Pumpkins', 'songname'=>'Soma'),
'2' => array('artist'=>'The Decemberists', 'songname'=>'The Island'),
'3' => array('artist'=>'Fleetwood Mac', 'songname' =>'Second-hand News')
);
The problem is thus: I’d like to echo out the songs I like in the format “Songname (Artist),” and I’d like to do it alphabetically by artist. PHP provides many functions for sorting arrays, but none will work here. ksort() will allow me to sort by key, but the keys in the $songs array are irrelevant. asort() allows me to sort and preserves keys, but it will sort $songs by the value of each element, which is also useless, since the value of each is “array()”. usort() is another possible candidate and can do multi-dimensional sorting, but it involves building a callback function and is often pretty long-winded. Even the examples in the PHP docs references specific keys.
So I developed a quick function to sort by the value of a key in a sub-array. Please note this version does a case-insensitive sort. See subval_sort() below.
function subval_sort($a,$subkey) {
foreach($a as $k=>$v) {
$b[$k] = strtolower($v[$subkey]);
}
asort($b);
foreach($b as $key=>$val) {
$c[] = $a[$key];
}
return $c;
}
To use it on the above, I would simply type:
$songs = subval_sort($songs,'artist');
print_r($songs);
This is what you should expect see:
Array
(
[0] => Array
(
[artist] => Fleetwood Mac
[song] => Second-hand News
)
[1] => Array
(
[artist] => The Decemberists
[song] => The Island
)
[2] => Array
(
[artist] => The Smashing Pumpkins
[song] => Cherub Rock
)
)
The songs, sorted by artist.
The answer to your question is indeed in the usort() function. However, what you need to do is write the function that you pass to it is doing the weighting for you properly.
Most of the time, you have something like
if($a>$b)
{
return $a;
}
But what you need to do is something along the lines of
if($a>$b || $someCountryID != 36)
{
return $a;
}
else
{
return $b;
}
You need to use ksort to sort by weight, not usort. That will be much cleaner.
Arrange your data in an associative array $weighted_data in the format weight => country_data_struct. This is a very intuitive form of presentation for weighted data. Then run
krsort($weighted_data)

$this->$array[$key] returning nothing when there is a value in place

I'm attempting to dynamically use a value in an array within an object.
In my particular case I have an array like this.
$this->customer = array(
[dealerId] => 4
[billFirstName] => Joe
[billLastName] => Blo
[billAddress1] => 1010s
[billAddress2] => 1020s
[billCity] => Anytown
[billState] => ST
[billCountry] => USA
[billPostalCode] => 11111
[dEmail] => emailaddress
[billPhone] => 8008008888
[password] => password
[distPrice] => 5
[distCost] => 20);
$result = $this->keyCheck('dealerId', 'customer');
The method I'm using:
protected function keyCheck($key, $array, $type = false)
{
if(array_key_exists($key, $this->$array) && $this->$array[$key]):
return $this->$array[$key];
else:
return $type;
endif;
}
The first check works (array_key_exists($key, $this->$array)). But the second check fails ($this->$array[$key]) even though there is a value held in that index of the array. I've proven that the array exists inside the keyCheck() method by using, print_r($this->$array); inside the method. And I know the value I'm looking for is available inside the method by using, print $this->$array['dealerId'];
Don't get hung up on the names, or the methodology I'm using, what I'm really interested in is finding out how to address a value held in an array that is dynamically addressed in this way.
It's probably so easy that I'll be slapping my head once it's revealed...
You are running into the dreaded treat string as an array trap, i.e.:
$str = 'customer'; echo $str[0]; // prints c
The $array[$key] portion of $this->$array[$key] is being interpreted as show me the nth index of string $array (if you pass customer it will try to access $this->c, which doesn't exist). Assign the array to a variable first. Here is an example:
class A
{
public $customer = array('dealerId'=>4, 'billFirstName'=>'Joe');
public function keyCheck($key, $arrayName, $type = false)
{
$array = $this->$arrayName;
if(array_key_exists($key, $array) && $array[$key]) {
return $array[$key];
} else {
return $type;
}
}
}
$a = new A();
echo $a->keyCheck('billFirstName', 'customer'); // Joe
Alternatively, you could use the complex syntax: $this->{$arrayName}[$key] as suggested in Artjom's answer.
PHP 5.4 addresses this gotcha:
[In PHP 5.4] Non-numeric string offsets - e.g. $a['foo'] where $a is a
string - now return false on isset() and true on empty(), and produce
a E_WARNING if you try to use them.
This E_WARNING should help developers track down the cause much more quickly.
Well u have to use
$this->{$array}[$key];

How to return a key=>value pair from a function in PHP

I need to return a key value pair from a function. It would be preferable to retain the structure of the data. I would like to avoid creating an array with only one value if possible as I do not care for the syntax key($result[0]) or an array with two values, as I would like something with a syntax or structure that suggests the key=>value relationship between the values. Is there a more elegant alternative to the array for returning multiple values from a function in php?
You can only use array(), really.
return array("key1" => "value1", "key2" => "value2");
Anything else would just be uglier or more confusing.
How about:
function getData () {
return array('key','value');
}
list($key,$value) = getData();
echo $key." = ".$value;
Although I must say, this sounds like a bizarrely specific and largely cosmetic requirement...
Could you not return the values in an array, like so?
return array('key' => $key, 'value' => $value);
You could also do this:
return array($key => $value);
But that's involves more work to use after the fact, in my opinion.
Return an array.
return array("key" => "value");
Here a full example proposed by #polynomial that might be interesting:
//Function declaration with a return of a key value pair array
function getUserRating(){
return array(
'rating' => $rating,
'average' => $average
);
}
// Retrieve one of the key value pair
getUserRating()['rating'];
// Retrieve the other key value pair
getUserRating()['average'];
Think this kind of magic only work with PHP 7 or further? OMG! It Works with PHP 5.4!
Am I misunderstanding your question, or do you not want return array('aKey' => 'aVal');?

In array returning the wrong result

I have the below array..
<?php $arrLayout = array(
"section1" => array(
"wComingEpisodes" => array(
"title" => "Coming Episodes",
"display" => ""
)
));
?>
Then I want to check if wComingEpisodes is in the array so..
<?php if (in_array( "wComingEpisodes" , $arrLayout )) {
echo "CHECKED";}
?>
However its returning nothing even though it is in the array. Do I need to do something different because of the multiple arrays or where is my mistake?
in_array tests for values, not keys. It also does not test nested values.
$arrLayout = array(
"section1" => array(
"wComingEpisodes" => array(
"title" => "Coming Episodes",
"display" => ""
)
));
echo array_key_exists(
"wComingEpisodes",
// this is the array you're actually looking for
$arrLayout['section1'] )?'exists':'does not exist';
you're getting the correct result according to the documentation.
if you want to search an multidimensional array recursive, take a look at the user contributed notes, where you can find examples like this, that show how to do a recursive search (which seems to be what you're looking for).
EDIT:
i just noticed you're trying to find out if a specific key exists: in this case, you'll have to use array_key_exists (like in_array, this also doesn't do a recursive search, so you'll have to do something like this).
in array searches array values.
the string, "wComingEpisodes", is the key of the value
you may want to try using array_key_exists()
In_array isn't recursive by nature so it will only compare the value you give it with the first level of array items of the array you give it.
Thankfully you're not the first with the problem so heres a function that should help you out. Taken from php.net in_array documentation
function in_arrayr($needle, $haystack) {
foreach ($haystack as $v) {
if ($needle == $v) return true;
elseif (is_array($v)) return in_arrayr($needle, $v);
}
return false;
}
http://www.php.net/manual/en/function.in-array.php#60696

Categories