Sometime I need to create key in a array if it don't exist.
For example:
$dataAgent['Paul'] = array('Sale' => 4,'Conv' => 1.5);
$dataAgent['Bill'] = array('Sale' => 6,'Conv' => 5.5);
$dataAgent['Tom'] = array('Sale' => 1);
$dataAgent['Jake'] = array('Sale' => 6,'Conv' => 10.5);
'Conv' key is missing in $dataAgent['Tom'] array.
I use the following code to check if 'Conv' key exist:
foreach($dataAgent as &$agent) {
if (!isset($agent['Conv'])) {
$agent['Conv'] = 0;
}
}
Is there alternative way instead of using foreach and better readability?
You will have to loop through the array one way or another, the key is not going to magically appear in all elements at once. You can just dress up the operation differently. My favourite would probably be:
$dataAgent = array_map(function (array $data) { return $data + array('Conv' => 0); }, $dataAgent);
Note that the + operator makes the use of isset unnecessary here.
The following are the solutions:
Put this key while forming your array. OR
Use array_walk($Your_array, "your_function");
function your_function($value, $key)
{
// put your logic here.
}
for more info: http://in3.php.net/array_walk
Related
I would like to check all keys of a global GET array and do something, if it contains keys, other than some whitelisted ones from an array.
Let's say the current url is:
.../index.php?randomekey1=valueX&randomkey2=valueY&acceptedkey1=valueZ&randomkey3=valueA&acceptedkey2=valueB
Just for better visualization:
These GET parameters are all available in the global GET variable which looks something like this:
$GET = array(
"randomekey1" => "valueX",
"randomkey2" => "valueY",
"acceptedkey1" => "valueZ",
"randomkey3" => "valueA",
"acceptedkey2" => "valueB"
);
The keys I accept and want to let pass, I put into an array too:
$whitelist = array(
"acceptedkey1",
"acceptedkey2",
"acceptedkey3",
);
Now I want to check whether $GET contains any key other than the whitelisted. So in the URL example from above it should return "true", because there are keys in the $GET array which aren't in the whitelist.
Not only the existence of such an unknown (none whitelisted) key should trigger a true, but please also its emptyness!
Another example would be the following url:
.../index.php?acceptedkey1=valueZ&acceptedkey3=valueB
This should return false, because no other key other than the ones in the whitelist were found.
Unfortunately I was not able to find any modification of the in_array function or array_search which would fit these requirements, because as far as I know these functions are only looking for something specific, whereas in my requirements I am also looking for something specific (the whitelist keys), but at the same tme I have to check if some unknown keys exist.
Thank you.
It seems you want to determine whether an array contains keys that don't exist in a whitelist.
One way to find the difference between arrays is to use array_diff():
array_diff ( array $array1 , array $array2 [, array $... ] ) : array
Returns an array containing all the entries from array1 that are not present in any of the other arrays.
So, it can be used to return all keys from the URL that are not present in the whitelist:
$extrasExist = !empty( array_diff( array_keys($GET), $whitelist ) );
var_dump($extrasExist);
Here's a demonstration:
$get1 = array(
"randomekey1" => "valueX",
"randomkey2" => "valueY",
"acceptedkey1" => "valueZ",
"randomkey3" => "valueA",
"acceptedkey2" => "valueB"
);
$get2 = array(
"acceptedkey1" => "valueZ",
"acceptedkey2" => "valueB"
);
$whitelist = array(
"acceptedkey1",
"acceptedkey2",
"acceptedkey3"
);
$extrasExist = !empty(array_diff(array_keys($get1),$whitelist));
var_dump($extrasExist);
$extrasExist = !empty(array_diff(array_keys($get2),$whitelist));
var_dump($extrasExist);
bool(true)
bool(false)
Everything in PHP doesn't have to be all "lets find function that does exactly what I'm looking for". Just do a simple foreach loop, which can accomplish what you're looking for:
function clear_filter() {
$whitelist = array( "project", "table_name", "filterDates", );
foreach ($_GET as $gkey => $gval) {
if (!in_array($gkey, $whitelist)) {
return false;
}
}
return true;
}
You can also write it more simply, with one foreach loop like below:
function isValid() {
// Copy the array
$temp = $_GET;
// Loop through the array, and remove any whitelisted elements
foreach ($whitelist as $wkey) {
unset($temp[$wkey]);
}
// If count($temp) > 0, there are non whitelisted entries in the array.
return count($temp) === 0;
}
You can use the following function.
$check = checkWhitliest( $_GET, $whitelist ) );
var_dump ($check );
You can call the above function as
function checkWhitliest( $array, $whitelist ) {
$allKeys = array_keys ( $array); //Get all Keys from the array.
$diff = array_diff( $allKeys, $whitelist); //Get the values which are not in whitelist.
if( count ( $diff ) > 0 ) { //If the count is greater than 0, then there are certain extra kesy in $_GET
return true;
}
return false;
}
There are only two techniques that I would recommend for this task and both make key comparisons for performance reasons. Using array_diff() or in_array() will always be slower than array_diff_key() and isset(), respectively, because of how PHP treats arrays as hash maps.
If you don't mind iterating the entire $GET array (because its data is relatively small), then you can concisely flip the whitelist array and check for any key differences.
var_export(
(bool)array_diff_key($GET, array_flip($whitelist))
);
If performance is more important than code brevity, then you should craft a technique that uses a conditional break or return as soon as a non-whitelisted key is encountered -- this avoids doing pointless iterations after the outcome is decided.
$hasNotWhitelisted = false;
$lookup = array_flip($whitelist);
foreach ($GET as $key => $value) {
if (isset($lookup[$key])) {
$hasNotWhitelisted = true;
break;
}
}
var_export($hasNotWhitelisted);
Or
function hasNotWhitelisted($array, $whitelist): bool {
$lookup = array_flip($whitelist);
foreach ($array as $key => $value) {
if (isset($lookup[$key])) {
return true;
}
}
return false;
}
var_export(hasNotWhitelisted($GET, $whitelist));
All of the above techniques deliver a true result for the sample data. Demo of all three snippets.
I have those two arrays that I added to attachments.
"PartnerAffiliateCodeId" from first array and "Id" from second array is our primary key.
"UserAction" must be counted for every unique "PartnerAffiliateCodeId" so in our case it is 5.
Normally I think this must be done by SQL but unfortunately this is a API method that I am receiving so I have to handle it by PHP.
Any ideas about how I can make such join with PHP using these two arrays?
I'm unclear on exactly what you're trying to get at with UserAction, but you could try something like this:
//$array1 = the first array
//$array2 = the second array
array_push($array_1, array(
"DateTime" => "",
"HttpReferer" => "",
"Id" => count($array1),
"PartnerAffiliateCodeId" => $array2["Id"],
"UserAction" => "Click"
));
It sounds like you want to match the ID key to the PartnerAffiliateCodeId in your returned data set.
Without knowing your setup, or bothinging with total optimization here a workable solution which will give you some direction.
function selectPartnerWhere($id=null; $from=array())
{
$codes = array();
foreach($from as $k => $p)
{
if($id == $p['PartnerAffiliateCodeId'])
{
return $from[$k];
}
}
return array();
}
$theData = //your array above
$thePartner = //your partner above
$partnerData = selectPartnerWhere($thePartner['Id'], $theData);
This question already has answers here:
How to search by key=>value in a multidimensional array in PHP
(17 answers)
Closed 9 years ago.
What would be the most efficient way of looking at an array of associative arrays, to find the node which meets a parameter?
I would like to have a more efficient way of looking through the array to find and return the parent node, that just looping through - looking at each element and returning if matched. (it is also safe to assume, that there are no duplicates of data - so the first found, is the only one found)
Or is a for loop the best thing ive got?
e.g.
array(
[0] => array('name' => 'fred'),
[1] => array('name' => 'dave'),
[2] => array('name' => 'mike)
)
And wanting to get the node of data where the name == 'dave' or to see if there is in fact a node which has a element name set as 'dave'.
e.g. somthing like
isset($data[]['name'] == 'dave')
$info = getdata($data[]['name'] == 'dave')
(Apologies if I'm not using the correct technical terms, please do correct me as I do like to learn!)
Many thanks in advance for any advice! =)
There is no better way than looping. PHP can't perform any magic that does not involve looking at each element in turn.
If you're doing this often, it helps to index your arrays by the search criterion:
$data = array(
array('name' => 'Dave'),
array('name' => ...)
);
$indexedData = array();
foreach ($data as $datum) {
$indexedData[$datum['name']] = $datum;
}
$info = $indexedData['Dave'];
As long as your data structure is sub-optimal, there's only sub-optimal ways to access it.
Here's a function for array recursion to one level. We use foreach() to loop through each second layer of child arrays, then use the built-in function array_search to see if it exists.
function as_nested($needle,$haystack){
$val;
foreach($haystack as $key=>$arr){
$arr_key = array_search($needle,$haystack[$key]);
if(!empty($arr_key)){
$val = $key;
}
}
return $val;
}
To execute, you supply the needle, then the haystack.
echo as_nested('dave',$myArray);
Output using your initial array is 1.
$myArray[0] = array('name'=>'fred');
$myArray[1] = array('name' => 'dave');
$myArray[2] = array('name' => 'mike');
There is a function in php called in_array() that looks for a value in an array.
//Code credit to #deceze
$data = array(
array('name' => 'Dave'),
array('name' => ...)
);
function getData($data, $searchValue) {
foreach ($data as $datum) {
if (in_array($searchValue, $datum)) {
return $datum;
}
}
//array returned when $searchValue is found.
You can use the getData function to search for a value in an array (this is not index specific. ie not restricted by only name, etc.)
I'm creating JSON encoded data from PHP arrays that can be two or three levels deep, that look something like this:
[grandParent] => Array (
[parent] => Array (
[child] => myValue
)
)
The method I have, which is simply to create the nested array manually in the code requires me to use my 'setOption' function (which handles the encoding later) by typing out some horrible nested arrays, however:
$option = setOption("grandParent",array("parent"=>array("child"=>"myValue")));
I wanted to be able to get the same result by using similar notation to javascript in this instance, because I'm going to be setting many options in many pages and the above just isn't very readable, especially when the nested arrays contain multiple keys - whereas being able to do this would make much more sense:
$option = setOption("grandParent.parent.child","myValue");
Can anyone suggest a way to be able to create the multidimensional array by splitting the string on the '.' so that I can json_encode() it into a nested object?
(the setOption function purpose is to collect all of the options together into one large, nested PHP array before encoding them all in one go later, so that's where the solution would go)
EDIT: I realise I could do this in the code:
$options['grandparent']['parent']['child'] = "myValue1";
$options['grandparent']['parent']['child2'] = "myValue2";
$options['grandparent']['parent']['child3'] = "myValue3";
Which may be simpler; but a suggestion would still rock (as i'm using it as part of a wider object, so its $obj->setOption(key,value);
This ought to populate the sub-arrays for you if they haven't already been created and set keys accordingly (codepad here):
function set_opt(&$array_ptr, $key, $value) {
$keys = explode('.', $key);
// extract the last key
$last_key = array_pop($keys);
// walk/build the array to the specified key
while ($arr_key = array_shift($keys)) {
if (!array_key_exists($arr_key, $array_ptr)) {
$array_ptr[$arr_key] = array();
}
$array_ptr = &$array_ptr[$arr_key];
}
// set the final key
$array_ptr[$last_key] = $value;
}
Call it like so:
$opt_array = array();
$key = 'grandParent.parent.child';
set_opt($opt_array, $key, 'foobar');
print_r($opt_array);
In keeping with your edits, you'll probably want to adapt this to use an array within your class...but hopefully this provides a place to start!
What about $option = setOption("grandParent", { parent:{ child:"myValue" } });?
Doing $options['grandparent']['parent']['child'] will produce an error if $options['grandparent']['parent'] was not set before.
The OO version of the accepted answer (http://codepad.org/t7KdNMwV)
$object = new myClass();
$object->setOption("mySetting.mySettingsChild.mySettingsGrandChild","foobar");
echo "<pre>".print_r($object->options,true)."</pre>";
class myClass {
function __construct() {
$this->setOption("grandparent.parent.child","someDefault");
}
function _setOption(&$array_ptr, $key, $value) {
$keys = explode('.', $key);
$last_key = array_pop($keys);
while ($arr_key = array_shift($keys)) {
if (!array_key_exists($arr_key, $array_ptr)) {
$array_ptr[$arr_key] = array();
}
$array_ptr = &$array_ptr[$arr_key];
}
$array_ptr[$last_key] = $value;
}
function setOption($key,$value) {
if (!isset($this->options)) {
$this->options = array();
}
$this->_setOption($this->options, $key, $value);
return true;
}
}
#rjz solution helped me out, tho i needed to create a array from set of keys stored in array but when it came to numerical indexes, it didnt work. For those who need to create a nested array from set of array indexes stores in array as here:
$keys = array(
'variable_data',
'0',
'var_type'
);
You'll find the solution here: Php array from set of keys
This is the set of result from my database
print_r($plan);
Array
(
[0] => Array
(
[id] => 2
[subscr_unit] => D
[subscr_period] =>
[subscr_fee] =>
)
[1] => Array
(
[id] => 3
[subscr_unit] => M,Y
[subscr_period] => 1,1
[subscr_fee] => 90,1000
)
[2] => Array
(
[id] => 32
[subscr_unit] => M,Y
[subscr_period] => 1,1
[subscr_fee] => 150,1500
)
)
How can I change the $plan[0] to $plan[value_of_id]
Thank You.
This won't do it in-place, but:
$new_plan = array();
foreach ($plan as $item)
{
$new_plan[$item['id']] = $item;
}
This may be a bit late but I've been looking for a solution to the same problem. But since all of the other answers involve loops and are too complicated imho, I've been trying some stuff myself.
The outcome
$items = array_combine(array_column($items, 'id'), $items);
It's as simple as that.
You could also use array_reduce which is generally used for, well, reducing an array. That said it can be used to achieve an array format like you want by simple returning the same items as in the input array but with the required keys.
// Note: Uses anonymous function syntax only available as of PHP 5.3.0
// Could use create_function() or callback to a named function
$plan = array_reduce($plan, function($reduced, $current) {
$reduced[$current['id']] = $current;
return $reduced;
});
Note however, if the paragraph above did not make it clear, this approach is overkill for your individual requirements as outlined in the question. It might prove useful however to readers looking to do a little more with the array than simply changing the keys.
Seeing the code you used to assemble $plan would be helpful, but I'm going assume it was something like this
while ($line = $RES->fetch_assoc()) {
$plan[] = $line;
}
You can simply assign an explicit value while pulling the data from your database, like this:
while ($line = $RES->fetch_assoc()) {
$plan[$line['id']] = $line;
}
This is assuming $RES is the result set from your database query.
In my opinion, there is no simpler or more expressive technique than array_column() with a null second parameter. The null parameter informs the function to retain all elements in each subarray, the new 1st level keys are derived from the column nominated in the third parameter of array_column().
Code: (Demo)
$plan = array_column($plan, null, 'id');
Note: this technique is also commonly used to ensure that all subarrays contain a unique value within the parent array. This occurs because arrays may not contain duplicate keys on the same level. Consequently, if a duplicate value occurs while using array_column(), then previous subarrays will be overwritten by each subsequent occurrence of the same value to be used as the new key.
Demonstration of "data loss" due to new key collision.
$plans = array();
foreach($plan as $item)
{
$plans[$item['id']] = $item;
}
$plans contains the associative array.
This is just a simple solution.
$newplan = array();
foreach($plan as $value) {
$id = $value["id"];
unset($value["id"]);
$newplan[$id] = $value;
}