Let's assume I have a table similar to this:
Id Name Value1 Value2 Value3
1 Bla 1 5 1
2 Blu 4 0 2
How to I put this into a matrix format (or similar) in PHP so I can work with it?
I wanted to do some calculations and sorting with the part that contains:
1 5 1
4 0 2
So I could then order and permantely change the main matrix. For example:
Assign a weight of 50% (or other) to each column and then move the columns associated with the lower values to the left.
Example:
1*0.5 + 4*0.5 = 2.5
5*0.5 + 0*0.5 = 2.5
1*0.5 + 2*0.5 = 1.5
Final output:
Id Name Value3 Value2 Value1
1 Bla 1 5 1
2 Blu 2 0 4
In C this was very easy to do but in PHP seems to me it's very complicated to do this because there isn't an object like M[i,j].
You need to access the column in each iteration of your query, you can't access it directly like you can with a row result:
$values = array();
$multiplier = 0.5;
foreach($result as $row) {
$values[1] += $row['value1'] * $multiplier;
$values[2] += $row['value2'] * $multiplier;
$values[3] += $row['value3'] * $multiplier;
}
print_r($values);
Depending on the names of your columns though, you could loop through them in PHP to define variables or array keys instead of doing it by hand (especially if you have lots of them). Depends on your column names. If you have lots that aren't related by numbers etc, you could loop through the column names and exclude certain ones e.g. id, name etc from your processing. In that case, you'd leave the first line above, insert a variable in place of 1 and value1, and check to make sure the array key exists before using the += operator as it will often throw an error if it's not already defined:
if(!array_key_exists($yourfield, $values))
$values[$yourfield] = 0;
// continue...
Related
I want to find Euclidean distance to check similarity of strings.
From above image in a painting object field there are many image types in database. Images is displaying using this paining_object field. Now i want to show related images of one selected image by comparing strings from paining_object field. So i have used Euclidean distance method to find similarities of strings.
But i am facing issue with length. For ex. In first row from database there are four image types in paining_object field and in the second row there are more than four image types. So, how could i measure distance with this method for the arrays having unequal length.
non euclidean distances
The distance between two unordered arrays can be rephrased as distance between sets.
A quick lookup shows there exists several distances representing the similarity between sets such as
the Jaccard distance
d(a,b) = |a inter b| / |a union b|
the maximum difference metric
d(a,b) = 1 - |a inter b| / max(|a|, |b|)
there are more distances (for instance) on the paper Distances between sets on set commonality
still euclidean distance
You can still force it:
Get all your mangas as a vocabulary V, say size n.
Consider the set R^n.
A row of your table can be represented as a vector v of R^n:
if the row contains word i, put v[i] = 1, v[i]=0 otherwise
Finally the euclidean distance can trivially be applied on the vectors of same length.
distance thus be like
d(a,b) = || v_b - v_a ||_2 = sqrt( (v_b[0] - v_a[0])^2 + ... + (v_b[n-1] - v_a[n-1)^2)
Every square is equal to 1 iff v_b[i]!=v_a[i] that is you want to count the elements in a not in b U b not in a idem the symmetric difference of a and b.
You can thus rewrite your distance:
d(a,b) = sqrt(|a Δ b|)
I have did this by using Jaccard distance as below. First created two tables for unique object from where we can collect object from id and second where all object comes together seperated from (,)
1) image_sub_main Table
2) image_main Table
3) PHP file as Wordpress Way
global $wpdb;
$post_id = $wpdb->get_results("SELECT * FROM `image_main`");
$i=1;
$finimgarray = array();
$aa = array();
$bb = array();
$firstarray = array('similarity' =>100 , 'id' => $post_id[0]->id );
foreach($post_id as $key => $post){
if($i < count($post_id)){
$arraya =$post_id[0]->image_types;
$a = explode(",",$arraya);
$arrayb =$post_id[$i]->image_types;
$b = explode(",",$arrayb);
$array = array_unique (array_merge ($a, $b));
$result=array_intersect($a,$b);
$finalres = count($result) / count($array)*100 ;
$finimgarray[] = array('similarity' =>round($finalres, 2) , 'id' => $post_id[$i]->id );
}
$i++;
}
array_push($finimgarray, $firstarray);
arsort($finimgarray);
foreach($finimgarray as $findimgarr){
$id = $findimgarr['id'];
$image = $wpdb->get_row("SELECT * FROM `image_main` WHERE `id` = $id ");
echo "<img src='$image->image'/>";
}
Your output will compare images to first one image and show according to similarity %
We cannot apply Euclidean Distance here because:
The array lengths can be different
The order of strings should not be considered. For example, hellsing
can be at any index in the array. So, we should not compare the first element of the first array with the first element of the second array only.
Instead, we can define a similarity function which takes care of both the above problems - we can use the ratio of number of string matches to the total number of combinations as the similarity score.
// Assuming $firstArr and $secondArr are sets, i.e., don't contain duplicates
function similarityScore($firstArr, $secondArr) {
$matchCount = 0;
foreach ($firstArr as $first) {
foreach($secondArr as $second) {
if ($first == $second) {
$matchCount++;
}
}
}
return $matchCount/(count($firstArr)*count($secondArr));
}
This function returns a real number in the range [0,1] where higher value indicates greater similarity.
I have a following array (php):
[
[id=>1,weight=]
[id=>2,weight=]
[id=>3,weight=]
[id=>4,weight=]
]
I need to create all possible versions of this array asigning 0-100 weight to each item['weight'] with a step of N.
I don't know how this type of problems are called. It is NOT permutation/combination.
Lets say N is 10, I am aiming to get:
[
[
[id=>1,weight=10]
[id=>2,weight=10]
[id=>3,weight=10]
[id=>4,weight=70]
]
[
[id=>1,weight=10]
[id=>2,weight=10]
[id=>3,weight=20]
[id=>4,weight=60]
]
[
[id=>1,weight=10]
[id=>2,weight=10]
[id=>3,weight=30]
[id=>4,weight=50]
]
[
[id=>1,weight=10]
[id=>2,weight=10]
[id=>3,weight=40]
[id=>4,weight=40]
]
...all possible combination of weights for id=x.
[
[id=>1,weight=70]
[id=>2,weight=10]
[id=>3,weight=10]
[id=>4,weight=10]
]
]
Sum of 4 item['weights'] in array on same level is always 100 (or 0.1). And inside parent array I've all possible combinations of weights from 10-100 for id=x.
This problem is sometimes described as allocating identical balls into distinct bins. You didn't specify your problem exactly, so I'll take a guess here but the logic will be identical.
I'll assume you're distributing b = N/step balls into 4 bins.
Think of the balls all in a row, and then using 3 bars to separate the balls into 4 bins:
*|||*****.
If N=10 and you're distributing 100 points, the above example is the same is 30, 20, 0, 50. If zeroes aren't allowed, you can reduce the amount you're distributing by 4*b and assume each bin starts out with N/step in it (so you're distributing the leftover points).
The number of ways to do this is choose(balls + bins - 1, bins - 1).
Theres probably a better way, but heres my attempt:
$result=array(); // Empty array for your result
$array=range(1117,7777); // Make an array with every number between 1117 and 7777
foreach ($array as $k=>$v) { // Loop through numbers
if ((preg_match('/[890]/',$v) === 0) && (array_sum(str_split($v, 1)) === 10)) {
// If number does not contain 8,9 or 0 and sum of all 4 numbers is 10
// Apply function to multiply each number by 10 and add to result array
$result[] = array_map("magnitude", str_split($v, 1));
}
}
function magnitude($val) { // function to multiply by 10 for array map
return($val * 10);
}
print_r($result);
Working demo here
EDIT
Sorry I realised my code explanation isn't totally clear and I condensed it all a bit too much to make it easy to follow.
In your example the first array would contain (10,10,10,70). For the sake of simplicity I divided everything by 10 for the calculations and then just multiplied by 10 once I had a result, so your array of (10,10,10,70) becomes (1,1,1,7). Then your final array would be (70,10,10,10) which would become (7,1,1,1).
My approach was to first to create an array containing every combination of these four numbers, which I did in two steps.
This line $array=range(1117,7777); creates an array like this (1117, 1118, 1119 ... 7775, 7776, 7777) (My number range should really have been 1117 - 7111 instead of 1117-7777).
Applying str_split($v, 1) to each value in the loop splits each 4 digit number in the array into another array conatining 4 single digit numbers, so 1117 will become (1, 1, 1, 7) etc
As each of your items can't have a weight below 10 or above 70 we use (preg_match('/[890]/',$v) === 0) to skip any arrays which have 0,8 or 9 in them anywhere, then array_sum(str_split($v, 1)) === 10) adds up the four digits in the array and only returns arrays which total 10 (you wanted ones which total 100, but I divided by 10 earlier).
array_map applies a function to each element in an array. In my example the function multiplies each value by 10, to undo the fact I divided by 10 earlier.
When you say is it possible to alter steps, can you give me a couple of examples of other values and the output you want for them?
If you want a totally different approach and using mysql isn't a problem then this also works:
Create a new table with a single row. Insert all the values you need to check
INSERT INTO `numbers` (`number`) VALUES
(10),
(20),
(30),
(40),
(50),
(60),
(70);
Then your php looks like this
$result=array();
try {
$dbh = new PDO('mysql:host=aaaaa;dbname=bbb', 'ccc', 'dddd');
foreach($dbh->query('SELECT *
FROM numbers a
CROSS JOIN // A cross join returns the cartesian product of rows
numbers b // so every row with every combination of the other rows
CROSS JOIN
numbers c
CROSS JOIN
numbers d
ON
a.number = b.number OR a.number != b.number') as $row) {
if (($row[0] + $row[1] + $row[2] + $row[3]) === 100) {
$result[] = $row;
}
}
$dbh = null;
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
print_r($result);
As the title what I'm trying to do is get numbers from database which I already do display them from descending order which I do. Patch numbers are in format X.XX so 2.01 2.05 2.22 and so on I want to label numbers between 2.00 - 2.highest one as Season 2 so Season 2 then patches like 2.99 2.85 2.04 2.00 etc.
My PHP:
foreach($patches as $patch)
{
if(substr($patch, -2)=="00"){
echo 'Season '.substr($patch, 0,1).'<br>';}
echo ''.$patch.'<br/>';
}
And my query:
$patches = $conn->prepare("SELECT Patch_No FROM info ORDER BY Patch_No DESC");
$patches->execute();
$patchesresult = $patches->get_result();
while($data1 = $patchesresult->fetch_assoc()){
$patch[$i]=$data1["Patch_No"];
$i+=1;
}
I probably have to check what is currently the highest patch so It could write first title Season XX
UPDATE - my 2D array:
$i=$j=0;
foreach($patches as $patch)
{
if($j!=0){
if(substr($patch, 0,1)!=substr($patch_array[$i][$j-1],0,1)){
$i+=1;
$j=0;
}
}
echo '$patch_array['.$i.']['.$j.'] '.$patch_array[$i][$j]=$patch.' substr$patch='.substr($patch, 0,1).' substr_previous: '.substr($patch_array[$i][$j-1],0,1).'<br/>';
$j+=1;
}
The array saves under [$i][$j] $i - is for patches with the same first number so 2.xx 2.xx 2.xx will be under the same $i and $j are for endings .01 .03 .04
so
[0][1] [0][2] [0][3] - {2.50 2.14 2.01}
[1][1] [1][2] [1][3] - {3.03 3.10 3.02}
Now I need to figure out displaying bit second loop
I changed up some syntax and variable names to make it a bit less confusing, but I think this is what you are going for. Also changed (improved) your query syntax.
$patches = $conn->prepare("SELECT Patch_No FROM info ORDER BY Patch_No DESC");
$patches->execute();
$patches->bind_result($patchNum);
$episodes=array();
while($patches->fetch_assoc()){
//build 1d array
$data=array($patchNum, substr($patch,0,1));
//push 1d array to array of arrays (2d array)
$episodes[]=$data;
echo '<a href="../index.php?Patch_No='.$patchNum.'"
class="patches"
>'.$patch.'</a><br/>';
}
Given an array of any size (from 1 to 4 rounds) with ranks numbering from 1 to 8 (or more), how can I take that array and sort it bracket style, so rank 1 is first, rank 2 is last, then rank 8 is next, then rank 7 is second to last... like
Then the next round ..
1, 4, 3, 2
I am trying to sort tournament brackets but not having much luck when it comes to sorting the ranking, and also in a way that scales well so the display does not break.
Edit:
Some clarification, each bracket size needs to break down like so:
If the bracket has 8 games, the game numbers are 1 through 8, so that round needs to arrange itself like:
Game 1
Game 8
Game 5
Game 4
Game 6
Game 3
Game 7
Game 2
So then, on the next round, it has 4 games, which would come out as:
Game 1
Game 4
Game 3
Game 2
And so on:
Game 1
Game 2
Finally,
Game 1
It also needs to work if the starting bracket had 16 games instead of 8, or 32, or more. The idea is that the winner of Game 1 and Game 8 play each other in Game 1 on the next round. The first game and second game are always the first and last on each bracket. Then it works it's way inward.
This isn't sorting the list. Unless you really need to sort the list, indices may be faster and more efficient.
The match ups will be set up like (current_rank), (total ranks) - (current_rank) + 1
Since there are 8 ranks,
1, 8 -1 +1 = 8
2, 8 -2 +1 = 7
3, 8 -3 +1 = 6
4, 8 -4 +1 = 5
So the code would look something like
<?php
$rankscount = count($ranks);
for ($i = 1; $i <= $rankscount / 2; $i++) {
echo "matchup will be: rank " . $i . " , rank " . $rankscount - $i + 1;
}
?>
After each round, reseed the function with the new sorted list, and you'll get 1vs4. 2vs3.
I'm not a professional at PHP, but hopefully this helps.
The following function sorts an array of ['r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8'] into an order of ['r1', 'r8', 'r2', 'r7', 'r3', 'r6', 'r4', 'r5'].
An array of ['r1', 'r2', 'r3', 'r4'] will be rearranged into ['r1', 'r4', 'r2', 'r3']
function rearranged($array) {
sort($array);
$result = array();
$length = count($array);
$offset = 0;
// Handling two elements at once, therefore just do $lenght/2 iterations
for ($i = 0; $i < $length/2; $i++) {
// $i + $offset: The current element in the original array
// + the offset of fields already filled in the results array
$result[$i + $offset] = $array[$i];
// $i + 1 + $offset: The next element in the results array
$result[$i + 1 + $offset] = $array[$length - $i -1];
// Increment offset
$offset++;
}
return $result;
}
I am not using any inbuilt sort function since they compare all keys to each others, assuming that your array already is in order just iterating and swapping positions should be much faster. If the keys are not ordered you can call a inbuilt sort function such as sort(sorts by value) or ksort (sorts by key).
To note is as well, that this function only works properly for arrays with an even amount of elements. If the number of elements is uneven the last element will be dropped from the results array.
I need to generate sequences of games using the round robin algorithm. I have the php page where the user can input the tournament name which will be inserted into the database and it has got a drop down menu up to 32 teams (select number of teams).
So if I select 4 teams in the page, so it will be from team 1 to team 4 which would be 6 matches because every team plays the other team once. I know how the algorithm works but I am not quite sure how to write the query for that.
I created the table team:
Team_id 01 02 03 etc
Team_name Team1 Team2 Team3 etc.
What should I do from here?
I created a roundrobin function from scratch as i thought it might be easier to get the same results and also allowing me to use arrays filled with strings directly instead of numbers.
Because i pull a list of names from a database and add into an array i can now schedule this directly with below function. No extra step needed to link numbers to names etc.
Please feel free to try it and if it works then leave a comment.
I also have a version which allows for 2 way (home & return) schedule and or shuffle option. If somone is interested in that one then leave a coment as well.
<?php
/**
* #author D.D.M. van Zelst
* #copyright 2012
*/
function scheduler($teams){
if (count($teams)%2 != 0){
array_push($teams,"bye");
}
$away = array_splice($teams,(count($teams)/2));
$home = $teams;
for ($i=0; $i < count($home)+count($away)-1; $i++){
for ($j=0; $j<count($home); $j++){
$round[$i][$j]["Home"]=$home[$j];
$round[$i][$j]["Away"]=$away[$j];
}
if(count($home)+count($away)-1 > 2){
array_unshift($away,array_shift(array_splice($home,1,1)));
array_push($home,array_pop($away));
}
}
return $round;
}
?>
How to use, for example create an array like:
<?php $members = array(1,2,3,4); ?>
or
<?php $members = array("name1","name2","name3","name4"); ?>
then call the function to create your schedule based on above array:
<?php $schedule = scheduler($members); ?>
To display the resulted array schedule simply do like below or anyway you like:
This little code displays the schedule in a nice format but use it anyway you like.
<?php
foreach($schedule AS $round => $games){
echo "Round: ".($round+1)."<BR>";
foreach($games AS $play){
echo $play["Home"]." - ".$play["Away"]."<BR>";
}
echo "<BR>";
}
?>
Leave a note if it worked for you or if you are interested in the 2-way version with shuffle.
There is a fairly simple algorithm for doing round-robin matchups, my solution would be as follows (in pseudo-code):
fetch all the teams out of the database into an array, in any order
for (i = 1; i < number of teams; i++)
print matchups for Round #i:
the teams in the first half of the array are matched up in the same order with the teams in the last half of the array. That is, the team at any index [n] is matched up with the team at index [n + half the number of teams]. If you have 32 teams, [0] is matched with [16], [1] with [17], etc up to [15] and [31].
Now, "rotate" the teams through the array, but leave the first one in the array in place. That is, [1] becomes [2], [2] becomes [3], ..., up to [31] becomes [1], but do not move the team at index [0].
And that's it, that will produce all the matchups you need.
An example, with 4 teams:
First half of the array is on top, second half is on the bottom, match-ups are numbers above/below each other. Array indexes (to illustrate what I mean exactly):
[0] [1]
[2] [3]
Round 1:
1 2
3 4
Round 2:
1 4
2 3
Round 3:
1 3
4 2