I have a table called "parents_kids", it has three columns known as:
id Guardian kids
1 Greg 1
2 Gary 3
3 Aaron 2
4 Farb 3
5 REX 1
6 Fred 2
In the following code I get it into array and print it:
$exc = $conn->prepare("SELECT ID,Guardian,kids from current_state");
$exc->execute();
while($finalResult = $exc->fetch(PDO::FETCH_ASSOC))
{
$tables[] = $finalResult;
}
var_dump($tables);
once i got this into an array, i sorted it in a custom order where
first the guardians with 2 kids, then with 1 kid and who has 3
ID Guardian kids
3 Aaron 2
6 Fred 2
1 Greg 1
5 REX 1
4 Farb 3
2 Gary 3
Now my requirement is to order this rest of the array according to its ID to descending order,
for example just like this
ID Guardian kids
6 Fred 2
3 Aaron 2
5 REX 1
1 Greg 1
4 Farb 3
2 Gary 3
i tried this many times but its dint work, the code i used to sort the first requirement is as follows
$order = array("2", "1", "3");
usort($tables, function ($a, $b) use ($order) {
$pos_a = array_search($a['kids'], $order);
$pos_b = array_search($b['kids'], $order);
return $pos_a - $pos_b;
});
can anybody help me to fullfil my second requirement which is sort the array by ID to descending order
This is how the array looks like
array (size=3)
0 =>
array (size=3)
'ID' => string '3' (length=1)
'Guardian' => string 'Aaron' (length=5)
'kids' => string '2' (length=1)
array (size=3)
1 =>
array (size=3)
'ID' => string '6' (length=1)
'Guardian' => string 'FRED' (length=4)
'kids' => string '2' (length=1)
etc
P.S doing it from the table is not going to work, because im using a loop above the code which makes it impossible to do it from the SQL, can anybody tell me a way to do it from the php
I think that it should help:
select ID,Guardian,kids
from current_state
order by case WHEN kids = 2 then 1
WHEN kids = 1 then 2
WHEN kids = 3 then 3
ELSE kids END ASC
, ID desc
There were two primary issues.
You were using status as the first key when it should have been kids based on your description.
You need to check whether the first subtraction was zero, and if so, compare the id values.
Here is a working solution.
$order = array("2", "1", "3");
usort($tables, function ($a, $b) use ($order) {
$pos_a = array_search($a['kids'], $order);
$pos_b = array_search($b['kids'], $order);
$result = $pos_a - $pos_b;
if ($result != 0) return $result;
return intval($b['ID']) - intval($a['ID']);
});
var_dump($tables);
Related
I am trying to work out how to correct display the rank of points to show a leaderboard.
I currently have the following in my Modal
public function getPointrankAttribute(){
$year = Carbon::parse(Carbon::now())->year;
$pointrank = Points::query()
->select('member_id')->selectRaw('SUM(value) as TotalPoints')
->where('Year','=', $year)
->groupBy('member_id')
->orderByDesc('Totalpoints')
->get();
return $pointrank->search(function($points){
return $points->member_id == $this->id;
}) + 1;
}
This works well, however it is using the row position in the table to show the rank, so the first record is 1st and the 2nd record shows as 2nd.
However the issue arises when members have the same total points, because under this the rank is based on position on in the table
See the following example
|member_id|totalpoints|
| 12 | 20 |
| 3 | 10 |
| 10 | 10 |
| 5 | 5 |
In this example based on my current solution
Member 12 = 1st, Member 3 = 2nd, Member 10 = 3rd, Member 5 = 4th
What I want is the following
Member 12 = 1st, Member 3 = 2nd, Member 10 = 2nd, Member 5 = 4th
It would be awesome if I could also add "=" as well when we have more than 1 member sharing that position (as in Member 3 and 10 in this case)
Thanks in advance
To get rank for your users you will need to assign rank to distinct total points first, using laravel collection helper you can create separate ranks collection irrespective of member ids like
$collection =collect(
[
[
"member_id" => 12,
"totalpoints" => 20
],
[
"member_id" => 3,
"totalpoints" => 10
],
[
"member_id" => 10,
"totalpoints" => 10
],
[
"member_id" => 5,
"totalpoints" => 5
],
]
);
$ranks = $collection->unique('totalpoints')
->values()
->mapWithKeys(function ($item, $index) {
return [$item['totalpoints'] => $index + 1];
});
Make sure the original collection should be ordered based on total points.
The above will create an array of distinct points as keys and values as ranks based on total points like
Array
(
[20] => 1
[10] => 2
[5] => 3
)
Now you can search your members based on id from original collection and get their respective rank from ranks array like
$id = 10;
$ranks[$collection->firstWhere("member_id", $id)["totalpoints"]];
There is another way to get ranks for your records directly from database if the vendor database supports window functions like RANK()
What I want is the following :Member 12 = 1st, Member 3 = 2nd, Member 10 = 2nd, Member 5 = 4th
To achieve your desired results you just need to remove ->values() from above code so that your results are not re indexed
$ranks = $collection->unique('totalpoints')
->mapWithKeys(function ($item, $index) {
return [$item['totalpoints'] => $index + 1];
});
Array
(
[20] => 1
[10] => 2
[5] => 4
)
DEMO
I have a table called "Current state", it has three columns known as:
id name state
1 FXD 1
2 GFX 3
3 ATOM 2
4 FARB 3
5 REX 1
6 FRX 2
In the following code I get it into array and print it:
$exc = $conn->prepare("SELECT name,state from current_state");
$exc->execute();
while($finalResult = $exc->fetch(PDO::FETCH_ASSOC))
{
$tables[] = $finalResult;
}
var_dump($tables);
But the problem is though numbers represent the state column values each of those numbers have a meaning:
1 = running
2 = finished
3 = dimnished
So what I want is to add the above string values right away to the tables array by comparing the values of the state column.
The current print result of a column would look like
array (size=2)
'name' => string 'FRX' (length=11)
'state' => string '2' (length=1)
But what I want is:
array (size=2)
'name' => string 'FRX' (length=11)
'state' => string 'finished' (length=8)
You can either do it in SQL with a CASE expression:
SELECT name,
CASE state
WHEN 1 THEN 'running'
WHEN 2 THEN 'finished'
WHEN 3 THEN 'diminished'
END AS state
FROM current_state
Or you could do it in PHP with an array:
$statemap = array(1 => 'running', 2 => 'finished', 3 => 'diminished');
Then your PHP loop would do the mapping:
while ($finalResult = $exc->fetch(PDO::FETCH_ASSOC)) {
$finalResult['state'] = $statemap[$finalResult['state']];
$tables[] = $finalResult;
}
Finally, you could have another table that contains the mappings, and join with it:
CREATE TABLE state_mappings (
state_num INT PRIMARY KEY,
state_name VARCHAR(20)
);
SELECT name, state_name
FROM state AS s
JOIN state_mappings AS m ON s.state = m.state_num
I have these tables. In the first table I have the transaction ID and the products bought in that transaction.
TID Products
1 1,2,5
2 2,4
3 2,3
4 1,2,4
5 1,3
6 2,3
7 1,3
8 1,2,3,5
9 1,2,3
What I want to do to this data is count the number of times an itemset occurs in the Products column. For example the itemset {1,2} is found 4 times in the Products column, there is no problem there, but 1,3 in only found 2 times but as it's seen in the Products column it appears 4 times.
ItemSet Sup. count
1,2 4
1,3 2
1,4 0
1,5 0
2,3 4
2,4 2
2,5 1
3,4 0
3,5 1
4,5 0
This is the php code that I used to find matches in the Sup. count column. if I make it find all coincidences in the itemset when I get to two digit numbers like 12 or more it will say that it found 1 and 2 again that is why I placed the boundary. So I am stuck at this place.
$result_support = array_fill ( 0 , $count_itemsets , 0 );
$count_result_array = count($result_array);
for($i = 0; $i < $count_itemsets; $i++){
for($j = 0; $j < $count_result_array; $j++){
$string = $result_array[$j];
if (preg_match('~\\b' . $result_itemset[$i] . '\\b~i', $string, $m)) {
$result_support[$i] = $result_support[$i] + 1;
}
}
}
$array1 = array(
1=> '1,2,5',
2 => '2,4',
3=> '2,3',
4 => '1,2,4',
5 => '1,3',
6=> '2,3',
7 => '1,3',
8 => '1,2,3,5',
9 => '1,2,3');
$produCt =array();
foreach ($array1 as $index =>$val){
$arra = explode(',', $val);
if(count($arra)>2){
for($i=0;$i<count($arra);$i++){
for($j=$i+1;$j<count($arra);$j++){
$produCt[] = $arra[$i].",".$arra[$j];
}
}
}else{
$produCt[] =$val;
}
}
$prdtCount =array_count_values($produCt);
var_dump($prdtCount);
I assume that your required output is
array (size=8)
'1,2' => int 4
'1,5' => int 2
'2,5' => int 2
'2,4' => int 2
'2,3' => int 4
'1,4' => int 1
'1,3' => int 4
'3,5' => int 1
I have these tables. In the first table I have the transaction ID and the products bought in that transaction.
TID Products
1 1,2,5
2 2,4
3 2,3
4 1,2,4
5 1,3
6 2,3
7 1,3
8 1,2,3,5
9 1,2,3
What I want to do to this data is count the number of times an itemset occurs in the Products column. For example the itemset {1,2} is found 4 times in the Products column, there is no problem there, but 1,3 in only found 2 times but as it's seen in the Products column it appears 4 times.
ItemSet Sup. count
1,2 4
1,3 2
1,4 0
1,5 0
2,3 4
2,4 2
2,5 1
3,4 0
3,5 1
4,5 0
This is the php code that I used to find matches in the Sup. count column. if I make it find all coincidences in the itemset when I get to two digit numbers like 12 or more it will say that it found 1 and 2 again that is why I placed the boundary. So I am stuck at this place.
$result_support = array_fill ( 0 , $count_itemsets , 0 );
$count_result_array = count($result_array);
for($i = 0; $i < $count_itemsets; $i++){
for($j = 0; $j < $count_result_array; $j++){
$string = $result_array[$j];
if (preg_match('~\\b' . $result_itemset[$i] . '\\b~i', $string, $m)) {
$result_support[$i] = $result_support[$i] + 1;
}
}
}
$array1 = array(
1=> '1,2,5',
2 => '2,4',
3=> '2,3',
4 => '1,2,4',
5 => '1,3',
6=> '2,3',
7 => '1,3',
8 => '1,2,3,5',
9 => '1,2,3');
$produCt =array();
foreach ($array1 as $index =>$val){
$arra = explode(',', $val);
if(count($arra)>2){
for($i=0;$i<count($arra);$i++){
for($j=$i+1;$j<count($arra);$j++){
$produCt[] = $arra[$i].",".$arra[$j];
}
}
}else{
$produCt[] =$val;
}
}
$prdtCount =array_count_values($produCt);
var_dump($prdtCount);
I assume that your required output is
array (size=8)
'1,2' => int 4
'1,5' => int 2
'2,5' => int 2
'2,4' => int 2
'2,3' => int 4
'1,4' => int 1
'1,3' => int 4
'3,5' => int 1
EDIT
solved ! it was my fault, the mysql query and the php method, both are working perfectly. my very bad example cunfused myself. aktually they should be sorting products by favorite ( true / false ) and then by date.
i'm trying to sort a multidimensional array by two "cols" but it just won't work for me :O
I've serched and copyed all possible ways ( mysql - order by, php - array_multisort() )
but it still won't work for me....
here is the method i've tryed first:
// MySQL Query
SELECT * FROM `test` ORDER BY `name` ASC, `age` DESC;
// or
SELECT * FROM `test` ORDER BY `name`, `age`;
// or
SELECT * FROM `test` ORDER BY name, age;
// or
SELECT * FROM `test` ORDER BY name, age DECT;
// `name` is VARCHAR and `age` is INT
so , i've tryed all possible syntax, but the query wont give me the wanted result.
the original table :
ID NAME AGE
---------------------
1 adam 23
2 bernd 30
3 cris 22
4 dora 21
5 anton 18
6 brad 36
7 sam 41
8 ali 13
what i want to get from MySQP Query :
ID NAME AGE
--------------------- // first sort by name...
8 ali 13 // then sort by age
5 anton 18 // ...
1 adam 23 // for each "similar" name or names with "a", "b", ...
2 bernd 30 // and so on...
6 brad 36
3 cris 22
4 dora 21
7 sam 41
but it actually gives my either sorted by NAME ( ORDER BY name, age ) or AGE ( ORDER BY age, name;
as i get frustrated, i've decidet to just get that query and sort it in PHP...
well, i've also tryed some codes but they all don't work either.
here is the one i aktually did now:
// this array is just exported from mysql to debug without mysql query...
$test = array(
array('id' => '1','name' => 'adam','age' => '23'),
array('id' => '2','name' => 'bernd','age' => '30'),
array('id' => '3','name' => 'cris','age' => '22'),
array('id' => '4','name' => 'dora','age' => '21'),
array('id' => '5','name' => 'anton','age' => '18'),
array('id' => '6','name' => 'brad','age' => '36'),
array('id' => '7','name' => 'sam','age' => '50'),
array('id' => '8','name' => 'ali','age' => '13')
);
// ...print out the original array
foreach( $test as $key => $value ) {
echo $value['name'] . " - " . $value['age'] . "<br>";
}
// here is the part where i am sorting...
$sort = array();
foreach ($test as $key => $value ) {
$sort['name'][$key] = $value['name'];
$sort['age'][$key] = $value['age'];
}
array_multisort($sort['age'], SORT_ASC, $sort['name'], SORT_DESC, $test);
// ...till here.
// reorder array and print the new sorted array
$sorted = array();
for( $i = 0; $i < count( $sort['name'] ); $i++ ) {
array_push( $sorted, array( $sort['name'][$i], $sort['age'][$i] ) );
echo $sort['name'][$i] . " - " . $sort['age'][$i] . "<br>";
}
but as you'll see if you test this, the sorting will just affect the AGE...
i dont know what i am doing wrong, prease tell me guys T_T
It appears to me that you only want to sort on the first char of the name:
You should try:
SELECT * FROM `test` ORDER BY SUBSTR(name,0,1), age;
What you encountered is absolutely expected behaviour. Why? If you sort first by name, you get results sorted for the full strings in the name column, where
'adam' < 'ali' < 'anton'
If there were more than one rows with name='adam', but different ages, like this:
ID NAME AGE
---------------------
1 adam 23
5 anton 18
8 ali 13
9 adam 52
You would get this result for SELECT * FROM test ORDER BY name, age;
ID NAME AGE
---------------------
1 adam 23
9 adam 52
8 ali 13
5 anton 18
As it is first sorted by name column, where the two adam values are the same, and then sorts based on the age, where 23 is smaller than 52...
But now, sorting on first character of name, and age SELECT * FROM test ORDER BY SUBSTR(name,0,1), age;:
ID NAME AGE
---------------------
8 ali 13
5 anton 18
1 adam 23
9 adam 52
If I unserstand you correctly, what you want to do is to sort just on the first letter of the name, then on the age. - What you have gotten from mysql is just what I would expect from your query and data set. If you choose several columns for sort, the secound kicks in only if you have equal values in the first one, eg if you had two Adams, one 18 and one 20 years old, the two would be sorted by age. and if you had Adam and Beth, both 18, Beth would come after Adam in the "sort by age,name"