Bottom line, I have a huge multidimensional array returned by ldap_get_entries that I am trying to parse into different groups based on the location attribute.
In PowerShell I could do something like:
$location1 = Get-ADUser -Filter * | ? {?_.l -eq "test_location"}
What I am currently doing within PHP (as far as my brain will let me go) is something like:
Foreach ($records as $record) {
if (isset($record['l'])) {
switch ($record['l'][0]) {
case "test_location1":
$location1[] = $record;
continue 2;
case "test_location2":
$location2[] = $record;
continue 2;
}
}
}
I then use a foreach loop (alternative syntax) against an array of location variables ($location1, $location2), that I used the above method, to sort records into their appropriate location variable. In this way, I build an HTML table grouping each locations records together. I build a new table for each location with some HTML code in between each group, so I don't believe sorting the ldap results by location will work, as it would output one large table.
Is there any way to specify a WHERE clause in PHP? So that I can assign all records in an array with a matching key value to variable1 and all records in an array with a different matching key value to variable2.
I am assuming I am tackling this in an amateur scripting way.. If there is an easier way to accomplish this task (maybe skipping the assign records to variables part), or any sort of "best practice" I am missing here, I am up for learning it.
Thanks in advance!!
As far as I understood your question you want something like this:
$recordsSorted = array();
foreach ($records as $record) {
if (! isset($record['l'])) {
continue;
}
$recordsSorted[$records['l'][0]][] = $record;
}
ksort($recordsSorted);
foreach($recordsSorted as $location => $records) {
usort($records, function($a, $b){
return strnatcasecmp($a['uid'][0], $b['uid'][0]);
});
echo '<h1>$location</h1><ul>';
foreach ($records as $record) {
echo '<li>' . $record['dn'] . '</li>';
}
echo '</ul>';
}
This will first put the first entry to the location-attribute of an entry as key of an array. That key can then be used to sort the array.
To output the content then it iterates over the new array and sorts the content - in this case using the first value of the uid-attribute (change the uid to whatever attribute you need). This sorted content is then output to HTML.
the first array $recordsSorted might look somewhat like this:
array(
'London' => array(
array(<entry from the LDAP>),
array(<another entry from LDAP>),
),
'Paris' => array(
array(<a further entry from the LDAP>),
),
'Berlin' => array(
array(<and even another entry from the LDAP>),
),
);
The result would then look somewhat like this:
<h1>Berlin</h1>
<ul>
<li>[UID of and even another entry from the LDAP]</li>
</ul>
<h1>London</h1>
<ul>
<li>[UID of another entry from LDAP]</li>
<li>[UID of entry from the LDAP]</li>
</ul>
<h1>Paris</h1>
<ul>
<li>[UID of a further entry from the LDAP]</li>
</ul>
Does that look like it could help you?
Related
I feel like i'm missing something quite simple. What are some of the best ways to iterate through combinations of $key names -- doing something different for each-- in a php foreach loop?
I have a number of values in an array with key values that follow the same naming format.
Example:
$rec_items['title3'] = implode($meta['title3']);
$rec_items['title4'] = implode($meta['title4']);
$rec_items['title5'] = implode($meta['title5']);
The $rec_items array also contains other values that do not follow this naming convention (or data type).
I'm looping through $rec_items with a foreach loop. I would like to be able to dynamically cycle through key names in $rec_items, and 'do something' when a key is found that matches title*. I've tried pushing numeric numbers from a counter variable into key names to be searched for (like below):
foreach ($rec_items as $key => $value){
$c = 0;
if(!empty($key[${'title'.$c}]){
$c++;
//do something
}
I believe that I cannot pass the value ${'title'.$c} into $key[] and have tried to pass the value of ${'title'.$c} as a string with no luck.
I just share the above to try to highlight what i'm trying to achieve.
(1) dynamically loop through key names in the format 'title*'
(2) if the key name is present in the $rec_items array ... do something.
I'm not sure what your original code was trying for; you appeared to be treating the array key like an array itself? Using a variable variable? Anyway, you just need a simple string search of the key. You can use regular expressions or whatever you like for more complex matching.
<?php
$rec_items = ["foo"=>12, "bar"=>34, "title1"=>56, "title2"=>78, "baz"=>90];
foreach ($rec_items as $k=>$v) {
if (strpos($k, "title") === 0) {
echo "$k = $v\n";
}
}
Output:
title1 = 56
title2 = 78
If you have any array $p that you populated in a loop like so:
$p[] = array( "id"=>$id, "Name"=>$name);
What's the fastest way to search for John in the Name key, and if found, return the $p index? Is there a way other than looping through $p?
I have up to 5000 names to find in $p, and $p can also potentially contain 5000 rows. Currently I loop through $p looking for each name, and if found, parse it (and add it to another array), splice the row out of $p, and break 1, ready to start searching for the next of the 5000 names.
I was wondering if there if a faster way to get the index rather than looping through $p eg an isset type way?
Thanks for taking a look guys.
Okay so as I see this problem, you have unique ids, but the names may not be unique.
You could initialize the array as:
array($id=>$name);
And your searches can be like:
array_search($name,$arr);
This will work very well as native method of finding a needle in a haystack will have a better implementation than your own implementation.
e.g.
$id = 2;
$name= 'Sunny';
$arr = array($id=>$name);
echo array_search($name,$arr);
Echoes 2
The major advantage in this method would be code readability.
If you know that you are going to need to perform many of these types of search within the same request then you can create an index array from them. This will loop through the array once per index you need to create.
$piName = array();
foreach ($p as $k=>$v)
{
$piName[$v['Name']] = $k;
}
If you only need to perform one or two searches per page then consider moving the array into an external database, and creating the index there.
$index = 0;
$search_for = 'John';
$result = array_reduce($p, function($r, $v) use (&$index, $search_for) {
if($v['Name'] == $search_for) {
$r[] = $index;
}
++$index;
return $r;
});
$result will contain all the indices of elements in $p where the element with key Name had the value John. (This of course only works for an array that is indexed numerically beginning with 0 and has no “holes” in the index.)
Edit: Possibly even easier to just use array_filter, but that will not return the indices only, but all array element where Name equals John – but indices will be preserved:
$result2 = array_filter($p, function($elem) {
return $elem["Name"] == "John" ? true : false;
});
var_dump($result2);
What suits your needs better, resp. which one is maybe faster, is for you to figure out.
I have a controller function in CodeIgniter that looks like this:
$perm = $this->job_m->getIdByGroup();
foreach($perm as $pe=>$p)
{
$pId = $p['id'];
$result = $this->job_m->getDatapermission($pId);
}
$data['permission'] = $result;
What I need to do is list the data in the result in the view, but I get only the last value while using this method. How can I pass all the results to the view?
Store it in an array. Like this:
foreach($perm as $pe=>$p){
$result[] = $this->job_m->getDatapermission($p['id']);
}
Because $result is not an array...
try this:
$result=array();
foreach($perm as $pe=>$p)
{
$pId = $p['id'];
$result[] = $this->job_m->getDatapermission($pId);
}
$data['permission'] = $result;
Note:
My answer uses a counter to enable the display of a single group result when needed.
Guessing from your need to loop and display the value of $result, possibly, it is an array or object returned by $query->result(). Things could be a bit complex.
Example: if $perm is an array of 5 items( or groups), the counter assigns keys 1 - 5 instead of 0 - 4 as would [] which could be misleading. Using the first view example, you could choose to display a single group value if you wants by passing it via a url segment. Making the code more flexible and reusable. E.g. You want to show just returns for group 2, in my example, $result[2] would do just that else next code runs. See my comments in the code.
$perm = $this->job_m->getIdByGroup();
$counter = 1;
foreach($perm as $pe=>$p)
{
$pId = $p['id'];
$result[$counter] = $this->job_m->getDatapermission($pId);
$counter++;
}
$data['permission'] = $result;
As mentioned above Note:
I Added a Counter or Key so you target specific level. If the groups are:
Men, Women, Boys, Girls, Children; you'd know women is group two(2) If you desire to display values for just that group, you don't need to rewrite the code below. Just pass the group key would be as easy as telling it by their sequence. To display all the loop without restrictions, use the second view example. To use both, use an if statement for that.
###To access it you could target a specific level like
if(isset($permission)){
foreach($permission[2] as $key => $value){
echo $value->columnname;
}
###To get all results:
foreach($permission as $array){
foreach($array as $key => $value){
echo $value->columnname;
}
}
}
foreach ( $this->parent->get_sections(null, $this->parent->author) as $section)
{
//...
}
I'm trying to do is force the loop to output each $section in the order I want. Each $section's name can be retrieved by $section->name. Let's say that I want to output $section "Section 2" first and then "Section 1" (and not in the order of the foreach). How can I force it do that? I presume the proper way would be a for loop with an if checking section names each time.
The proper way would be sorting the results when you call parent->get_sections(). How you would do this is entirely up to the implementation of that class and method. Changing this foreach to for for the sake of sorting seems like a code smell to me.
For the sake of answering the question as technical as possible.
$sections = $this->parent->get_sections(null, $this->parent->author);
$num_sections = count($sections);
for ($i = 0; $i < $num_sections; $i++) {
// what you do here is up to you $sections[$i]
}
Especially if you are not aware of the specific number of sections, you could use usort() to do a dynamic custom sort on the get_sections()-returned array or object and then utilize the existing code. (This is a little more elegant, imo, than doing the same in a for/foreach loop).
Not knowing the structure of your code, I would do something like.
// Get Org Sections
$sections = $this->parent->get_sections(null, $this->parent->author);
// Loop thru sections to get an array of names
foreach ( $sections as $key=>$section)
{
$sorted_sections[$section->name] = $key;
}
// Sort Array
//ksort — Sort an array by key
//krsort — Sort an array by key in reverse order
krsort($sorted_sections);
foreach ( $sorted_sections as $section)
{
// Orig Code
}
$section = $this->parent->get_sections(null, $this->parent->author);
echo $section[2]->name;
echo $section[1]->name;//just output the indexes the way you want
if you want it sorted, in say descending order, you can sort it that way and then use a for loop to display.
I have a working script, but I'm sure that my method of managing arrays could be better. I've searched for a solution and haven't found one, but I'm sure that I should be using the functionality of associative arrays to do things more efficiently.
I have two arrays, one from a CSV file and one from a DB. I've created the CSV array as numeric and the DB array as associative (although I'm aware that the difference is blurry in PHP).
I'm trying to find a record in the DB array where the value in one field matches a value in the CSV array. Both arrays are multi-dimensional.
Within each record in each array there is a reference number. It appears once in the CSV array and may appear in the DB array. If it does, I need to take action.
I'm currently doing this (simplified):
$CSVarray:
('reference01', 'blue', 'small' ),
('reference02', 'red', 'large' ),
('reference03', 'pink', 'medium' )
$Dbarray:
(0 => array(ref=>'reference01',name=>"tom",type=>"mouse"),
(1 => array(ref=>'reference02',name=>"jerry",type=>"cat"),
(2 => array(ref=>'reference03',name=>"butch",type=>"dog"),
foreach ($CSVarray as $CSVrecord) {
foreach ($Dbarray as $DBrecord) {
if ($CSVarray[$numerickey] == $DBrecord['key'] {
do something with the various values in the $DBrecord
}
}
}
This is horrible, as the arrays are each thousands of lines.
I don't just want to know if matching values exist, I want to retrieve data from the matching record, so functions like 'array_search ' don't do what I want and array_walk doesn't seem any better than my current approach.
What I really need is something like this (gibberish code):
foreach ($CSVarray as $CSVrecord) {
WHERE $Dbarray['key']['key'] == $CSVrecord[$numerickey] {
do something with the other values in $Dbarray['key']
}
}
I'm looking for a way to match the values using the keys (either numeric or associative) rather than walking the arrays. Can anyone offer any help please?
use a hash map - take one array and map each key of the record it belongs to, to that record. Then take the second array and simply iterate over it, checking for each record key if the hashmap has anything set for it.
Regarding your example:
foreach ($DBarray as $DBrecord){
$Hash[$record[$key]] = $DBrecord;
}
foreach ($CSVarray as $record){
if (isset($Hash[$record[$CSVkey]])){
$DBrecord = $Hash[$record[$CSVkey]];
//do stuff with $DBrecord and $CSVrecord
}
}
this solution works at O(n) while yours at O(n^2)...
You can use foreach loops like this too:
foreach ($record as $key => $value) {
switch($key)
{
case 'asd':
// do something
break;
default:
// Default
break;
}
}
A switch may be what you are looking for also :)
Load CSV into the db, and use db (not db array) if possible for retrieval. Index the referenceid field.