php sort merge arrays - php

I have a list of (xml) items, each item has a category and a name:
Category | Name
1 | Joe
2 | Carol
3 | Bruce
1 | Michael
1 | Alan
2 | Brian
I want to sort the names ascending within categories descending like so:
Category | Name
3 | Bruce
2 | Brian
2 | Carol
1 | Alan
1 | Joe
1 | Michael
with the aim of creating a Select dropdown on a web page with each category as an OptGroup and the names sorted within the OptGroup.
I have very little experience with PHP, I think I need to sort merge arrays, but after many hours trying to understand how to, I'm not making much progress.
Any help greatly appreciated

$data[] = array('category' => 1, 'name' => 'Joe');
$data[] = array('category' => 2, 'name' => 'Carol');
$data[] = array('category' => 3, 'name' => 'Bruce');
$data[] = array('category' => 1, 'name' => 'Michael');
$data[] = array('category' => 1, 'name' => 'Alan');
$data[] = array('category' => 2, 'name' => 'Brian');
<?php
// Obtain a list of columns
$category =array();
$name =array();
foreach ($data as $key => $row) {
$category[$key] = $row['category'];
$name[$key] = $row['name'];
}
// Sort the data with category descending, name ascending
// Add $data as the last parameter, to sort by the common key
array_multisort($category, SORT_DESC, $name, SORT_ASC, $data);
echo '<pre>'; print_r($category);
?>

Hi thanks to everybody for your help including all the other Stackoverflow questions which I googled to piece this together, not sure how I did it, bit of a case of an infinite number of monkeys or should that be newbies, anways here's what worked for me.
Sorts names ascending within contributions descending
function compare($a, $b) {
if ($a['contribution'] == $b['contribution']) {
return ($a['name'] < $b['name']) ? -1 : 1;
} else {
return ($b['contribution'] - $a['contribution']);
}
}
usort($ads_by_cotribution, 'compare');
It's all magic to me, that's the beauty of it. I didn't include the case of names being equal
'cause there shouldn't be any and as I understand equal values would still stay together just in a different order. I'd like to understand how these functions work, do they continuously walk through the array until there's no change in the order - what we used to call a bubble sort? Does ($b['contribution'] - $a['contribution']) indicate which is the larger? Finley is there a difference between sorting contributions - a numeric field and names - an alpha field?

$name = array("Joe", "Carol", "Bruce", "Michael","Alan","Brian");
sort($name);
php-in built function sort will produce desire result

Related

PHP/MYSQL - Counting and comparing entries in a myqsl table with php

I was wondering if anybody can help me out/point me in the right direction.
I have a database with a table that includes incremental id, name, unique id, and the parent uuid of fictional characters.
The table shows the following people...
John (Parent not listed)
Steve (Parent listed as John)
Mark (Parent listed as John)
Kevin (Parent listed as Steve)
Adam (Parent listed as Mark)
**ID, NAME, UUID, PARENT_UUID**
1, John, 0001, none
2, Steve, 0002, 0001
3, Mark, 0003, 0001
4, Kevin, 0004, 0002
5, Adam, 0005, 0003
So in this example, John has 2 sons, Steve and Mark... each of whome have a son, Kevin and Adam.
What I want to do, is (on an already made profile page) show the number of family members.
So going to Johns page, I would see "John (4 Descendents)", and if I went to Marks page, I'd see "Mark (1 Descendents)"
Allowing me to list how many family members, in lower generations are found in the table.
I am able to print a list of all family members... using:
$sql = "SELECT * FROM users";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
echo $row["uuid"]. "<br>";
}
}
But now I want to find out for each $row['uuid'] how many descendents each entry has.
I tried doing something like the following:
$sql = "SELECT * FROM users";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
$sql = "SELECT * FROM users WHERE parent_uuid = '".$row['uuid']."'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
$numOfDescendents = $result->num_rows;
}
}
}
But then I realised that not only does this not work (it grabs the number of the first row and stops), that using this logic, if I have a family with 20+ generations, I'm going to need to have 20+ while loops nested within each other, checking each generation.
So I'm wondering, is this even possible?
There's probably an easy way, but after 3/4 days of headaches and frustration I'm finally asking for help =)
My end goal is to have a php file that checks through the table for all users, and totals their descendents by counting how many people in the table use their uuid as a parent_uuid... as in the example at the start... John would have 4, Mark would have 1, Steve would have 1, Kevin would have 0, and Adam would have 0.
Thanks in advance for any guidance =)
You can use a recursive function to solve this. Note - I am passing the entire input to the recursive array which I do not recommend. If you are using a class set the input as a property of the class or you can use global which is also not recommended.
$input = [
['id' => 1, 'name' => 'John', 'UUID' => 0001, 'PARENT_UUID' => null],
['id' => 2, 'name' => 'Steve', 'UUID' => 0002, 'PARENT_UUID' => 0001],
['id' => 3, 'name' => 'Mark', 'UUID' => 0003, 'PARENT_UUID' => 0001],
['id' => 4, 'name' => 'Kevin', 'UUID' => 0004, 'PARENT_UUID' => 0002],
['id' => 5, 'name' => 'Adam', 'UUID' => 0005, 'PARENT_UUID' => 0003],
];
function getDescendents($uuid, $input, $count = 0, $descendants = [])
{
foreach ($input as $user) {
if ($user['PARENT_UUID'] === $uuid) {
$count++;
$descendants[] = $user['UUID'];
}
}
if (!empty($descendants)) {
$new_uuid = array_shift($descendants);
return getDescendents($new_uuid, $input, $count, $descendants);
}
return $count;
}
$result = [];
foreach ($input as $user) {
$result[$user['name']] = getDescendents($user['UUID'], $input);
}
echo(json_encode($result));
Output -
{"John":4,"Steve":1,"Mark":1,"Kevin":0,"Adam":0}
The key in the above object is the user's name and the value is the number of descendants.

Raking Result of search query

Rank Result data set
i am building meta search tool which get results from different sources in response to user query. i have saved the results in array of object having information like title, description , release date etc.before showing it on interface i want to rank them, so that most relevant result should be on top just like search engines. but i am new to ranking and don't know about it. so kindly guide me in this matter which ranking algorithm i should follow or any useful link for help.
I think you need to add "weighting" column (can be null) on your array of Object and just before to show the elements you need to loop on weighting if they got one.
Then your results will be shown in first and if no weight just the normal display.
Here an example :
<?php
//Function to compare weightings
function cmp($a, $b) {
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
$searches = array(
'songs'=> array(
0 => array(
'title' => 'coldplay',
'weight'=> 3
),
1 => array(
'title' => 'eminem',
'weight'=> 2
),
2 => array(
'title' => 'rihanna',
'weight'=> 2
),
3 => array(
'title' => 'shakira',
'weight'=> 1
),
4 => array(
'title' => 'nirvana',
'weight'=> null
),
5 => array(
'title' => 'acdc'
)
),
);
//this foreach is used to apply the weighting on itterations
foreach($searches['songs'] as $key => $search){
//if no weight of weight is null
if(array_key_exists('weight', $search) && $search['weight']){
$array_by_weight[$key]['weight'] = $search['weight'];
$array_by_weight[$key]['title'] = $search['title'];
}else{
$array_by_weight[$key]['weight'] = 5; //Value max of weighting
$array_by_weight[$key]['title'] = $search['title'];
}
}
//We use our function to compare and sort our array
uasort($array_by_weight, 'cmp');
//display
foreach($array_by_weight as $songs){
echo $songs['title'].' | ';
echo $songs['weight'].PHP_EOL;
}
Output :
shakira | 1
eminem | 2
rihanna | 2
coldplay | 3
acdc | 5
nirvana | 5
I hope it can help you.

PHP combine two arrays in foreach loop

I need guidance on how to combine two arrays in foreach loop. I have a list of checkboxes that will add user to corresponding list.
To grab my checkboxes as an array using :
<input type="checkbox" name="checkbox_list[]" value="Austin Metro">
<input type="checkbox" name="checkbox_list[]" value="Central Austin">
<input type="checkbox" name="checkbox_list[]" value="Georgetown">
...
Here is my loop:
foreach($_POST['checkbox_list'] as $check) {
$myValues = array('Austin Metro','Central Austin','Georgetown','Lake Travis | Westlake','Leander | Cedar Park','Northwest Austin','Round Rock | Pflugerville | Hutto','San Marcos | Buda | Kyle','Southwest Austin','DFW Metro','Frisco','Grapevine | Colleyville | Southlake','McKinney','Plano','Houston Metro','Conroe | Montgomery','Cy-Fair','Katy','Pearland | Friendswood','Spring | Klein','Sugar Land | Missouri City','Tomball | Magnolia','The Woodlands');
$myIds = array('3','4','5','6','7','8','9','10','11','25','12','13','14','15','24','16','17','18','19','20','21','23','22');
if (isset($check) && array_search($check, $myValues) !== false){
$index = array_search($check, $myValues);
$indeed_mail->indeed_wysija_subscribe( $myIds[$index], $email );
}
}
Currently it is adding user to the right list but is sending one email confirmation per list, instead of merging all subscribed lists in one single email.(in other words if user selects "Austin" & "Houston" lists, it will get one email for "Austin" and one email for "Houston")
Any suggestions on how to fix? Thanks!
Here is function that add subscriber and sends email confirmation:
public function indeed_wysija_subscribe( $listId, $e_mail, $first_name='', $last_name='' ){
$user_data = array(
'email' => $e_mail,
'firstname' => $first_name,
'lastname' => $last_name);
$data = array(
'user' => $user_data,
'user_list' => array('list_ids' => array($listId))
);
$helper = &WYSIJA::get('user', 'helper');
if($helper->addSubscriber($data)) return 1;
else return 0;
}
You should define the array with checkbox names/IDs outside of your loop, and use a more appropriate structure for them:
$map = array (
3 => 'Austin Metro',
4 => 'Central Austin',
5 => 'Georgetown',
6 => 'Lake Travis | Westlake',
7 => 'Leander | Cedar Park',
8 => 'Northwest Austin',
9 => 'Round Rock | Pflugerville | Hutto',
10 => 'San Marcos | Buda | Kyle',
11 => 'Southwest Austin',
25 => 'DFW Metro',
12 => 'Frisco',
13 => 'Grapevine | Colleyville | Southlake',
14 => 'McKinney',
15 => 'Plano',
24 => 'Houston Metro',
16 => 'Conroe | Montgomery',
17 => 'Cy-Fair',
18 => 'Katy',
19 => 'Pearland | Friendswood',
20 => 'Spring | Klein',
21 => 'Sugar Land | Missouri City',
23 => 'Tomball | Magnolia',
22 => 'The Woodlands',
);
Now you can even remove the loop completely and continue with this code:
// take from map only those entries that have been checked:
$checks = array_intersect($map, $_POST['checkbox_list']);
// pass the IDs of those values to the emailing class:
$indeed_mail->indeed_wysija_subscribe( array_keys($checks), $email );
You just now need to adapt that indeed_wysija_subscribe so it can deal with arrays. There is only one line to change:
'user_list' => array('list_ids' => $listId)
Notice that array($listId) becomes just $listId because that argument is now already an array.
PHP have array_combine function
http://php.net/manual/en/function.array-combine.php
Ignoring the Title of your questions and focusing on the question asked.
Currently it is adding user to the right list but is sending one email confirmation per list, instead of merging all subscribed lists in one single email.
You need to collate the user ids selected, before you pass it into the subscribe function.
Currently your calling the subscribe function, indeed_wysija_subscribe, inside the foreach loop foreach($_POST['checkbox_list'] as $check) {.
You need to move the subscribe call outside the loop and pass in an array of $listId.
This may require you to modify the indeed_wysija_subscribe function to support the array. Or there may be another function in the library.
I am not sure what is part of the library or not.
Also, you can perform the mapping between city name to numeric id in more direct manner.
$myValues = array('Austin Metro','Central Austin','Georgetown');
$myIds = array('3','4','5','6');
$cityToIdMap = array(
'Austin Metro'=>'3',
'Central Austin'=>'4',
'Georgetown'=>'5'
);
$subscriberIds = array();
foreach($_POST['checkbox_list'] as $check) {
if(!empty($check) && isset($cityToIdMap[$check])){
$subscriberIds[] = $cityToIdMap[$check];
}
}

Inserting multiple arrays into different rows

I'm collecting input fields as an array to be inserted into the different rows in the database. However it only inserts the first row of the array.
Please kindly assist. I have some issues handling arrays. I don't know how to construct the query and I've tried to search online and I couldn't get enough help. I'll really appreciate help with the query.
Here is my HTML code:
<input type = "text" class = "form_element" name = "wat_office_type[]" />
<input type = "number" name = "wat_office_price[]" class = "form_element" />
while I use jQuery to add more input boxes.
Here is my php:
$wat_office_type_post = $_POST['wat_office_type'];
$wat_office_price_post = $_POST['wat_office_price'];
$wat_office_type = array();
$wat_office_price = array();
foreach ($wat_office_type_post as $type) {
if (!empty($type))
$wat_office_type[] = $afrisoft->antiHacking($type);
}
foreach ($wat_office_price_post as $post) {
if (!empty($post))
$wat_office_price[] = $afrisoft->antiHacking($post);
}
I want to insert into 2 separate rows and achieve something like this:
--------------------------------------------
| Pk | wat_office_type | wat_office_price |
--------------------------------------------
| 1 | executive office | 1000 |
--------------------------------------------
| 2 | Training room | 4000 |
--------------------------------------------
| 3 | Events room | 5000 |
--------------------------------------------
I'll kindly appreciate if I can get help with the insert query (mysql,php) on how I can insert all values of the first array in one column, and values of the second array into the second column, while each are matching d numbers of arrays supplied.
Thanks.
If I understand correctly, you need to combine the two arrays into something like
$list = array(
array('pk' => 1, 'type' => 'executive', 'price' => 1000),
array('pk' => 2, 'type' => 'training room', 'price' => 4000),
array('pk' => 3, 'type' => 'events room', 'price' => 5000)
);
then you can call a foreach loop to query the database with each element, like
foreach($list as $key => $value) {
$sql = "INSERT INTO table_name (pk, type, price) VALUES (?, ?, ?)";
$query = $this->db->prepare($sql);
$params = array($value['pk'], $value['type'], $value['price']);
if($query->execute($params)) {
return true;
} else {
return false;
}
}
so instead doing two foreach loops and putting results in different arrays, you could use one foreach loop and create an associative array for each set of results (I assume the count on both of your arrays is the same?) as I mentioned above.

Merge meta table with main table

I have two tables, a main one, and one that supports the main table, very very similar to what wordpress has, posts and posts_meta.
Main table:
id
title,
content
id | title | content
1 | one | content one
2 | two | content two
Meta table:
id
item_id
key
value
id | item_id | key | value
1 | 1 | template | single
2 | 1 | group | top
1 | 2 | template | page
2 | 2 | group | bottom
And my goal is, in the end, have an array with the data from the main table, merged with the meta table. example:
$data = array(
array(
'id' => 1,
'title' => 'one',
'content' => 'content one',
'template' => 'single',
'group' => 'top'
),
array(
'id' => 2,
'title' => 'two',
'content' => 'content two',
'template' => 'page',
'group' => 'bottom'
)
);
What is the best way to achieve this in a way that preforms good?
I am using PDO to connect to my database, and how Im doing right now is, I first query the data on the first table, and then for each result, i query the meta table, I use prepared statements for this, since it's suposed to be fast, but even so, it's harming the performance of my script.
Thank you
Instead of querying meta table for each result from first query
you should extract the ids from the first result:
$rows = q('SELECT * FROM posts');
$byIds = [];
foreach ($rows as &$row)
{
$byIds[$row['id']] =& $row;
}
and run second query:
$rows2 = q('SELECT * FROM posts_meta WHERE item_id IN (' . implode(',', array_keys($byIds)) . ')');
Then loop the results in PHP and merge with first query results.
foreach ($rows2 as $row2)
{
$byIds[$row2['item_id']][$row2['key']] = $row2['value'];
}
You have your merged results in $rows variable now:
var_dump($rows);
This way you will have only 2 db requests.
Please note that i have used $byIds as array of references so i dont have to search row with specific id in second loop. This way order of elements in $rows are preserved.

Categories