I have an array that has this format:
array(
info(
Date-today => '09/04/2013'
)
clients(
id => 1001,
name => Fred
)
more_info(
weather-today => "cloudy"
)
)
But sometimes, I receive the data with more clients:
array(
info(
Date-today => '08/04/2013'
)
clients(
0(
id => 1001,
name => Fred
),
1(
id => 1045,
name => Fritz
)
)
more_info(
weather-today => "Sunny"
)
)
I want to count how many cients I got returned, because I need to access the client-data differently if there is only one or more then one.
I tried several "count()" options, such as:
count(array['client'])
but of course if there is only 1 client, it doesn't return 1, it returns 2 (since there are 2 items of client-data in the array).
Any tips?
You would have to find out whether $array['clients'] has only numeric indices:
$size = count($array['clients'];
if (count(array_filter(array_keys($array['clients']), 'is_int')) == $size) {
return $size;
} else {
return 1;
}
Alternatively, use the existence of one numeric index as the condition:
if (isset($array['clients'][0])) {
return count($array['clients']);
} else {
return 1;
}
If you have an array-like structure (as the collection of clients in your example), you should always index the entries, even if there is only one entry.
That way you don't end up with the problem you described.
EDIT:
Didn't see your comment.
You can first check if $array['clients'] has any content (via count()).
-> If it hasn't, cnt = 0.
Then check if $array['clients']['0'] is defined.
-> If it isn't defined, cnt = 1.
-> If it is, cnt = count().
Related
I have this PHP array:
$this->user_list = array( 0 => 'Not paid',1 => 'Not paid', 2 => 'Not paid', 7 => 'Waiting, 15 => 'Waiting', 10 => 'Cancelled' );
How can I simplify this array as the id numbers are different, but some of them have same status?
I tried it like this:
$this->user_list = array( [0,1,2 => 'Not paid'],[7,15 => 'Waiting'],10 => 'Cancelled' );
but it doesn't work as expected.
Basically I want to achieve this:
echo $this->user_list[15] should give me Waiting, echo $this->user_list[10] should give me Cancelled, etc. So this is working in my first array very well, I am just thinking about grouping duplicate names there.
As mentioned by other contributors, there is no native support in the PHP grammar for your intended use case. As clearly stated in the PHP: Arrays documentation:
An array can be created using the array() language construct. It takes any number of comma-separated key => value pairs as arguments.
So basically each element in an array is a key => value pair, which means you cannot associate multiple keys to a single element.
This also explains why your first tentative didn't work:
$this->user_list = array( [0,1,2 => 'Not paid'],[7,15 => 'Waiting'],10 => 'Cancelled' );
If you don't specify a key for an element, PHP uses a progressive index (0, 1, ...). So basically in the example above, the first zero is not actually a key, but a value, and PHP binds it to the key = 0. Maybe it could be easier for you to understand how it works if you print a var_dump or print_r of $this->user_list. You would get something similar to the following structure (NOTE: I have simplified the structure to make it more clear):
[
0 => [
0 => 0
1 => 1
2 => "Not paid"
],
1 => [
0 => 7,
15 => "Waiting"
],
10 => "Cancelled"
]
So how do we resolve this problem? Well... actually there is no need to contort the structure by swapping keys with values as other contributors seem to suggest. Changing the structure might simplify your "data entry" work but might also create big issues in other parts of the program because who knows, maybe accessing the invoice data by "ID" is simply more efficient than by "status" ... or something.
Since PHP does not provide such a feature out of the box, I believe a better solution would be to develop our own function; a good starting point could be the one in the example below.
function explode_array($config, $sep = ',') {
$res = [];
foreach($config as $configKey => $value) {
// split key values
$keys = explode($sep, $configKey);
foreach($keys as $key) {
$res[$key] = $value;
}
}
return $res;
}
$config = [
'0,1,2' => 'Not paid',
'7,15' => 'Waiting',
'10' => 'Cancelled'
];
$myArr = explode_array($config);
print_r($myArr);
The idea is quite simple: since we cannot use an array as key we leverage the next best data type, that is a CSV string. Please note there is no error handling in the above code, so the first thing you may want to do is adding some validation code to the explode_array (or however you wish to name it) function.
you should use like this. if id number is invoice id or something else and other value is there status about it.
$arr = array(
'Not paid' => [0,1,2] ,
'Waiting' => [5,6],
'Cancelled' =>[8]
);
foreach($arr as $key => $val){
foreach($val as $keys => $vals){
echo "invoiceid ".$vals ." status ".$key;
echo"<br>";
}
}
// for only one status you can use like this
foreach($arr['Not paid'] as $key => $val){
echo $val;
echo"<br>";
}
just try to run this and check output.
PHP has no built-in function or structure for handling cases like this. I'd use a simple array value-cloning function to map your duplicates. Simply have one instance of each status, then map the aliases, and then run a function that clones them in. As follows:
// Status list:
$ulist = [ 0 => 'Not paid', 7 => 'Waiting', 10 => 'Cancelled' ];
// Alternative IDs list, mapped to above source IDs:
$aliases = [ 0 => [1,2], 7 => [15] ];
// Function to clone array values:
function clone_values(array &$arr, array $aliases)
{
foreach($aliases as $src => $tgts) {
foreach($tgts as $tgt) {
$arr[$tgt] = $arr[$src];
}
}
ksort($arr); // If the order matters
}
// Let's clone:
clone_values($ulist, $aliases);
This results in the following array:
array(6) {
[0] · string(8) "Not paid"
[1] · string(8) "Not paid"
[2] · string(8) "Not paid"
[7] · string(7) "Waiting"
[10] · string(9) "Cancelled"
[15] · string(7) "Waiting"
}
....which can be accessed as you expect, here $ulist[2] => Not paid, etc. If the use case is as simple as illustrated in the OP, I'd personally just spell it out as is. There's no dramatic complexity to it. However, if you have dozens of aliases, mapping and cloning begins to make sense.
As said in the comments, you can't have multiple keys with one value. The best way is to use the keyword => [ number, number, number...] construction.
//set a result array
$result = [];
//loop the original array
foreach ( $this->user_list as $number => $keyword ){
//if the keyword doesn't exist in the result, create one
if(!isset ( $result [ $keyword ] ) ) $result[ $keyword ] = [];
//add the number to the keyword-array
$result[ $keyword ] [] = $number;
}
Simple one, but still can't figure out.
I have two arrays of slightly different structures.
The first array contains members (as first level indexes, e.g. 4, 2) and their document ids (as second level indexes, e.g. 2, 3) and department tags for those documents:
array (
4 =>
array (
2 => 'support',
),
2 =>
array (
3 => 'billing',
),
)
The second array's first level index doesn't have any meaning, so could be get rid of. However, the second level index contains member ids (e.g. 4, 2) and department tags those members opened access to (the current user):
array (
0 =>
array (
4 =>
array (
'support' => 'support',
'billing' => 'billing',
),
),
1 =>
array (
2 =>
array (
'support' => 'support',
),
),
)
So I am trying to compile a list of documents that should be displayed to the current user.
For example, since member #4 has given access to support and billing the current user should be able to see document #2 (tagged as support) from that member.
And because member #2 has given access to only support tagged documents, the current user should not be able to see document #3 (tagged as billing).
So the above example should give only:
array(2)
How do I generate the final array of documents in PHP comparing two arrays?
It's possible to do what you want with loops and searches, but I'd consider this data structure unmaintainable and aim for changing it in the first place. Well, sometimes you can't, so here's how I'd do it:
$documents_data =[
4 => [2 => 'support'],
2 => [3 => 'billing']
];
$access_data = [
[4 => ['support' => 'support', 'billing' => 'billing']],
[2 => ['support' => 'support']]
];
// You need current user's data so having his id
// extract his access rights from second array
$user_id = 4;
function userData($user_id, $access_table) {
$access = [];
foreach ($access_table as $user_acc) {
if (key($user_acc) !== $user_id) { continue; }
$access = reset($user_acc);
break;
}
return [
'id' => $user_id,
'access' => $access
];
}
$user = userData($user_id, $access_data);
// Filter out documents (if any) not matching user's access rights
function userDocuments($user, $docs) {
if (empty($docs[$user['id']])) { return []; }
return array_filter(
$docs[$user['id']],
function ($doc_type) use ($user) {
return isset($user['access'][$doc_type]);
}
);
}
$allowed_docs = userDocuments($user, $documents_data);
Here is my code that I am working on to create an array so the end product will return the following:
$values=user_email => displayname
user_email => displayname
user_email => displayname
I am using the array listed below:
array [0] => std.class Object( [id] = 12
[user_login] = bob
)
[1] => std.class Object( [id] = 15
[user_login] = frank
)
When I run my code that is listed below it only runs on the last value. I have tried using the "." at the variable name but it only seems to add it to the variable instead of the array where I need it.
What I hope to do is:
Run a wp_user_query to return all the personnel in a group
get the results
after I get the results, use the [id] for each user to determine their $displayname and $email
they are then sent into a new array using their email as key
Here is the code that I have been working on, and as of right now it does everything correctly except return every user, it only returns the last user
function show_user_dropdown($values, $field){
if( $field->id == 155 ){
$wp_user_search = new WP_User_Query( array( 'role' => 'Hrrepresentative', 'fields' => array('user_login', 'ID') ) );
$authors = $wp_user_search->get_results();
$value['options']=array();
foreach ($authors as $a) {
$displayname=get_the_author_meta('display_name', $a->ID);
$emailname=get_the_author_meta('user_email', $a->ID);
$validation=array($emailname=>$displayname);
$values['options']=$validation;
$values['use_key'] = true;
}
}
return $values;
}
What do I need to do to fix this?
You have both 'values' and 'value'. I don't think the array notation is working how you think it is. I think you'd be better off doing something like this:
$values[$id]['option'] = $validation;
edit: to elaborate, you only have 1 value for $values (the last run through the foreach loop). You also would be overwriting the previous value in $values['option'] regardless. You need to use a multidimensional array with an index.
To get the array structure you showed, try:
$values['options'][$emailname] = $displayname;
You are reassigning $values['options']=$validation; in your loop.
Use it this way:
$values['options'][]=$validation;
I like how CakePHP automatically loops through the results of MySQL queries and formats them in a nice map for you.
Here's a sample query that I'm using:
# Inside some model
return $this->query("
SELECT
Profile.id,
SUM( IF( HOUR(Log.event_one) > 3, 1, 0 ) ) as EventOne
FROM profiles Profile
JOIN logs Log ON Log.id = Profile.log_id
WHERE Profile.id = {$pUserId}
");
CakePHP would return a map like the following as the result:
array
0
array
'Profile'
array
'id' => 23
'0'
array
'EventOne' => 108
1
array
'Profile'
array
'id' => 23
'0'
array
'EventOne' => 42
2
...
What I'm trying to do is have the result be something like this:
array
'Profile'
array
'id' => 23
'Events'
# ^ I want to be able to specify this key
array
'EventOne' => 108
Any ideas?
You can't do that directly
The top level array keys are derived from the table name which mysql says the field relates to - in your case it's a calculated field and therefore (according to mysql) belongs to no table - hence the 0 array key.
Post processing
What you can do however, is post process the result so that it is the format you want:
public function getStuff() {
// The query call in the question can very easily be a normal find call
$return = $this->query("don't use query unless you have no choice");
foreach($return as &$row) {
$row['Events'] = $row[0];
unset($row[0]);
}
return $return;
}
Given this multidimensional array, I'm trying to retrieve the value of one of the child keys:
$movieCast = Array(
'1280741692' => Array(
...
, 'userid' => 62
, 'country_id' => '00002'
...
)
, '1280744592' => Array(
...
, 'userid' => 62
, 'country_id' => '00002'
...
)
)
How can I retrieve the value of country_id?
The top-level array key could be anything and the value of country_id will always be the same for a specific user. In this example, user #62's country_id will always be 00002.
You have to iterate through the outer array:
foreach ($outer as $inner) {
//do something with $inner["country_id"]
}
Another option is to build an array with the contry_ids (example uses PHP >=5.3 functionality, but that can be worked around easily in earlier versions):
array_map(function ($inner) { return $inner["country_id"]; }, $outer);
EDIT If the ids are all the same, even easier. Do:
$inner = reset($outer); //gives first element (and resets array pointer)
$id = $inner["country_id"];
a more general-purpose solution using php 5.3:
function pick($array,$column) {
return array_map(
function($record) use($column) {
return $record[$column];
},
$array
);
}
You need to use this:
array_column($movieCast, 'country_id')
The result will be:
array (
0 => '00002',
1 => '00002',
)