Feature like FB's "X, Y and Z other people like this" - php

I'm trying to implement something like facebook's like widget which says something like:
You, Name1, Name2 and 20 other people like this
I fetched all my data to be able to display this HTML, but I can't seem to find the right algo to form the HTML string.
My main problem is that I don't know when to put the and string or the , (comma) string. If I just had to put names, it would work, but the problem is that the You string always has to be first.
I'm going to paste my code here and the output I'm getting for some special cases (it's PHP).
$current_user = 0;
$html = "";
$count = count($result);
$key = 0;
foreach($result as $liked){
if($key + 1 > $limit)
break;
if($liked->uid == $user->uid){
$current_user = 1;
continue;
}
$html .= "<a href='".$liked->href."'>".$liked->name."</a>";
if($key < $count - 2)
$html .= ", ";
elseif($key == $count - 2 && $key + 1 != $limit)
$html .= " and ";
$key++;
}
if($current_user){
$userHtml = "You";
if($count > 2)
$userHtml .= ", ";
elseif($count > 1)
$userHtml .= " and ";
$html = $userHtml.$html;
}
$html = "♥ by ".$html;
if($count > $limit){
$difference = $count - $limit;
$html .= " and ".$difference." ".format_plural($difference,"other","others");
}
return $html;
And in the special case where the current user is the last one to like this, it will show:
♥ by You, admin, edu2004eu and
Notice the and word doesn't have anything after it, because You should have been after it, but I put it at the beginning. Any help? I just need the logic, not the actual code.

You can try something like this:
$likedBy = array('admin', 'eduard', 'jeremy', 'someoneelse');
// check if I like it and if so move me to the front
if (in_array($currentUsername, $likedBy)) {
$me = array_search($currentUsername, $likedBy);
unset($likedBy[$me]);
array_unshift($likedBy, 'You');
}
// remove anything after the limit
$extra = array_splice($likedBy, 3);
// the comma list
$html = implode(', ', $likedBy);
// any extras? if so, add them here, if not rewrite the list so
// it's "You, Eduard and admin"
if (!empty($extra)) {
$html .= ' and '.count($extra);
} else {
$lastguy = array_splice($likedBy, 1);
$html = implode(', ', $likedBy).' and '.$lastguy;
}
$html .= ' like this';

Eduard,
You can fix this simply by putting $key++; at the top of the loop and taking out all the places where you have $key + 1 in the loop.
I think what's happening is that $key + 1 is assuming that there is a current user.
This line would also not display the current user if they are not in the first $limit number of entries
if($key + 1 > $limit)
break;
You can fix this by putting this after the code that looks for the current user.
In Java (I know, but its what I had running) it would look something like:
List<String> users = Arrays.asList("Brian","Tom","Jack","John");
int key = 0;
String html = "";
String currentUser = "Brian";
int limit = 3;
boolean foundCurrentUser = false;
for (String user : users) {
key ++;
if (currentUser == user) {
foundCurrentUser = true;
continue;
}
if (key > limit) {
continue;
}
html += user;
if (key < users.size() - 1) {
html += ",";
} else if (key == users.size() - 1 && key != limit) {
html += " and ";
}
}
if (foundCurrentUser) {
String userHTML = "You";
if (key > 2) {
userHTML += ", ";
} else if (key == 1) {
userHTML += " and ";
}
html = userHTML + html;
}
html = "Likeed by " + html;
if (users.size() > limit ) {
html += " and 3 other people";
}
System.out.println(html);

Related

Php apply function in array if next entry is integer (Concatenate a valid FEN string)

Trying to build a valid FEN string.
Given this 8*8 array example, symbolizing a checker board, ("1" are empty squares):
$checkerboard = [["r","n","b","q","k","b","n","r"],["p","p","p","p","p","p","p","p"],["1","1","1","1","1","1","1","1"],["1","1","1","1","1","1","1","1"],["1","1","1","1","P","1","1","1"],["1","1","1","1","1","1","1","1"],["P","P","P","P","1","P","P","P"],["R","N","B","Q","K","B","N","R"]]
In situ, this is the position:
The valid result I am looking for is:
rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR
And by now my output is:
rnbqkbnr/pppppppp/11111111/11111111/1111P111/11111111/PPPP1PPP/RNBQKBNR
Obviously, any integer entry in the array should be sum to the next, only if the next entry is an integer, and if so the next entry should be discarded till the end.
By iterating the array, I am not sure how to apply something like array_walk() or array_map() here in a simple way. Maybe a simple string operation is enough?
$FEN = "";
for ($i = 0;$i < 8;$i++){
for ($j = 0;$j < 8;$j++){
if ($checkerboard[$i][$j] === "1"){
if ($checkerboard[$i][$j + 1] === "1"){
/* How to iterate till the end */
$FEN .= (int)$checkerboard[$i][$j] + (int)$checkerboard[$i][$j+1];
}
} else {
$FEN .= $checkerboard[$i][$j];
}
}
$FEN .= "/";
}
Any insights?
Example online: https://3v4l.org/tuqqo
$checkerboard = [["r","n","b","q","k","b","n","r"],["p","p","p","p","p","p","p","p"],["1","1","1","1","1","1","1","1"],["1","1","1","1","1","1","1","1"],["1","1","1","1","P","1","1","1"],["1","1","1","1","1","1","1","1"],["P","P","P","P","1","P","P","P"],["R","N","B","Q","K","B","N","R"]];
$parts = array();
foreach ($checkerboard as $innerArray) {
$num = null;
$str = '';
foreach($innerArray as $innerval){
if(is_numeric($innerval)){
$num += (int) $innerval;
}
else{
if(!is_null($num)){
$str .=$num;
$num = null;
}
$str .=$innerval;
}
}
if(!is_null($num)){
$str .=$num;
}
array_push($parts,$str);
}
$result = implode('/',$parts);
above code will generate required output and store it on the $result.

Joining a string with input fields = one value

how can I get this result as a value of LUC-1701-000005 field I made ..
I get the current value from one field ($value = $_POST['wpuef_options']['c26'];), but I want to make it easier for customers to not enter those LUCs ... than just numbers..
current code looks like this ..
for($I=0; $I<= 5; $I++){
if($I == 0){
$value = $_POST['wpuef_options']['c26'];
}
else if($I == 1){
$value = $_POST['wpuef_options']['c30'];
}
else if($I == 2){
$value = $_POST['wpuef_options']['c34'];
}
else if($I == 3){
$value = $_POST['wpuef_options']['c44'];
}
else if($I == 4){
$value = $_POST['wpuef_options']['c50'];
}
this is something I need ..but this is not correct ..
$value = "LUC-" + $_POST['wpuef_options']['c26'] + "-" + $_POST['wpuef_options']['c23'];
Try this:
$value = "LUC-" . $_POST['wpuef_options']['c26'] . "-" . $_POST['wpuef_options']['c23'];
You are using + for concatenation, which is wrong, in PHP it is just . .

How to reliably find similar strings to that typed in

I have an interface where a user will enter the name of a company. It then compares what they typed to current entries in the database, and if something similar is found it presents them with options (in case they misspelled) or they can click a button which confirms what they typed is definitely new and unique.
The problem I am having is that it is not very accurate and often brings up dozens of "similar" matches that aren't that similar at all!
Here is what I have now, the first large function I didn't make and I am not clear on what exactly it does. Is there are much simpler way to acheive what I want?
// Compares strings and determines how similar they are based on a nth letter split comparison.
function cmp_by_optionNumber($b, $a) {
if ($a["score"] == $b["score"]) return 0;
if ($a["score"] > $b["score"]) return 1;
return -1;
}
function string_compare($str_a, $str_b)
{
$length = strlen($str_a);
$length_b = strlen($str_b);
$i = 0;
$segmentcount = 0;
$segmentsinfo = array();
$segment = '';
while ($i < $length)
{
$char = substr($str_a, $i, 1);
if (strpos($str_b, $char) !== FALSE)
{
$segment = $segment.$char;
if (strpos($str_b, $segment) !== FALSE)
{
$segmentpos_a = $i - strlen($segment) + 1;
$segmentpos_b = strpos($str_b, $segment);
$positiondiff = abs($segmentpos_a - $segmentpos_b);
$posfactor = ($length - $positiondiff) / $length_b; // <-- ?
$lengthfactor = strlen($segment)/$length;
$segmentsinfo[$segmentcount] = array( 'segment' => $segment, 'score' => ($posfactor * $lengthfactor));
}
else
{
$segment = '';
$i--;
$segmentcount++;
}
}
else
{
$segment = '';
$segmentcount++;
}
$i++;
}
// PHP 5.3 lambda in array_map
$totalscore = array_sum(array_map(function($v) { return $v['score']; }, $segmentsinfo));
return $totalscore;
}
$q = $_POST['stringA'] ;
$qLengthMin = strlen($q) - 5 ; // Part of search calibration. Smaller number = stricter.
$qLengthMax = strlen($q) + 2 ; // not in use.
$main = array() ;
include("pdoconnect.php") ;
$result = $dbh->query("SELECT id, name FROM entity_details WHERE
name LIKE '{$q[0]}%'
AND CHAR_LENGTH(name) >= '$qLengthMin'
#LIMIT 50") ; // The first letter MUST be correct. This assumption makes checker faster and reduces irrelivant results.
$x = 0 ;
while($row = $result->fetch(PDO::FETCH_ASSOC)) {
$percent = string_compare(strtolower($q), strtolower(rawurldecode($row['name']))) ;
if($percent == 1) {
//echo 1 ;// 1 signifies an exact match on a company already in our DB.
echo $row['id'] ;
exit() ;
}
elseif($percent >= 0.6) { // Part of search calibration. Higher deci number = stricter.
$x++ ;
$main[$x]['name'] = rawurldecode($row['name']) ;
$main[$x]['score'] = round($percent, 2) * 100;
//array_push($overs, urldecode($row['name']) . " ($percent)<br />") ;
}
}
usort($main, "cmp_by_optionNumber") ;
$z = 0 ;
echo '<div style="overflow-y:scroll;height:175px;width:460px;">' ;
foreach($main as $c) {
if($c['score'] > 100) $c['score'] = 100 ;
if(count($main) > 1) {
echo '<div id="anysuggested' . $z . '" class="hoverdiv" onclick="selectAuto(' . "'score$z'" . ');">' ;
}
else echo '<div id="anysuggested' . $z . '" class="hoverdiv" style="color:#009444;" onclick="selectAuto(' . "'score$z'" . ');">' ;
echo '<span id="autoscore' . $z . '">' . $c['name'] . '</span></div>' ;
$z++ ;
}
echo '</div>' ;
Comparing strings is a huge topic and there are many ways to do it. One very common algorithm is called the Levenshtein difference. This is a native implementation in PHP but none in MySQL. There is however an implementation here that you could use.
You need aproximate/fuzzy string matching.
Read more about
http://php.net/manual/en/function.levenshtein.php, http://www.slideshare.net/kyleburton/fuzzy-string-matching
The best way would be to use some index based search engine like SOLR http://lucene.apache.org/solr/.

Mysql search string

I have a search box that will search for a keyword in the field : description
then return results. its done in mysql and php.
the description can go from 10 to 600 characters long. I would like to return only a part of result.
for example :
I am searching for the keyword= John
instead of displaying the whole field description as the result I want to see the sentence where the keyword is found only: ... Hello my name is john and I ...
not the whole paragraph.
I can use sql or php whichever one is better. I tried substring but failed implementing it any example would be great.
SELECT SUBSTR(description,2,100)
FROM screenplays
WHERE lower(description) like '% $search_word_fix %'
I thought by query, it will hamper performance. Because of string calculations. So I have done this by php substr function logic.
SELECT description
FROM screenplays
WHERE lower(description) like '% $search_word_fix %'
//$description will have longer string.
//$short_string will have shorter string.
$short_string=get_less_string($description,'john',20);
function get_less_string($string,$key,$num){
$desc=explode($key,$string);
$left='...'.substr($desc[0], strlen($desc[0])-$num,$num);
$right=substr($desc[1],0,$num).'...';
$final_string=$left.$key.$right;
return $final_string;
}
if you want to use php.. I had written a function few months back. It searches for keywords in a text and returns a string with 'bold' keywords. Hope this helps.
$str = 'I have a search box that will search for a keyword in the field : description then return results. its done in mysql and php. the description can go from 10 to 600 characters long. I would like to return only a part of result. for example : I am searching for the keyword= John instead of displaying the whole field description as the result I want to see the sentence where the keyword is found only: ... Hello my name is john and I ... not the whole paragraph.
I can use sql or php whichever one is better. I tried substring but failed implementing it any example would be great.';
$search = array();
$search[] = "example";
echo descriptionSearch($str,$search);
function descriptionSearch($desc,$words,$max_number_words = 30)
{
$descs = explode(" ",$desc);
$positions = array();
$i = 0;
foreach($words as $w)
{
$j = 0;
foreach($descs as $d)
{
$w = strtolower(trim($w));
$d = strtolower(trim($d));
if(strpos($d,$w) !== false)
{
$positions[] = $j;
$descs[$j] = str_replace($w,"<span style='font-weight: bold;'>".$d."</span>",$d);
}
$j++;
}
$i++;
}
$max = 0;
if(sizeof($positions) > 0)
{
foreach($positions as $j)
{
if($max < 4)
{
$i = $j -5;
if($i < 0)
{
$i = 0;
}
while($i < ($j+10))
{
$toreturn .= $descs[$i]." ";
$i++;
}
$toreturn .= " ...";
$max++;
}
}
}
else
{
for($i=0; $i < $max_number_words; $i++)
{
$toreturn .= $descs[$i]." ";
}
}
return $toreturn;
}
You CAN do it either way, and both will be about as efficient. PHP is probably a better more flexible solution, but just for kicks I tried to do it in MySQL, to see how it would work
SELECT SUBSTR(
description,
if(INSTR(description, '$search_word_fix') - 10 < 0,
0,
(INSTR(description, '$search_word_fix') - 10)),
if(
INSTR(description, '$search_word_fix') + 10 >
length(description),
length(description),
NSTR(description, '$search_word_fix') + 10))
FROM screenplays
WHERE lower(description) LIKE '% $search_word_fix %'
Modified answer, This can search better. In this example. I am searching for 'for example' or 'john'
$str = 'I have a search box that will search for a keyword in the field : description then return results. its done in mysql and php. the description can go from 10 to 600 characters long. I would like to return only a part of result. for example : I am searching for the keyword= John instead of displaying the whole field description as the result I want to see the sentence where the keyword is found only: ... Hello my name is john and I ... not the whole paragraph.
I can use sql or php whichever one is better. I tried substring but failed implementing it any example would be great.';
$search = array();
$search[] = "for example";
$search[] = "john";
echo descriptionSearch($str,$search);
function descriptionSearch($desc,$words,$max_number_words = 30)
{
$positions = array();
$i = 0;
foreach($words as $w)
{
$w = strtolower(trim($w));
$d = strtolower(trim($d));
if(strpos($desc,$w) !== false)
{
$positions[] = strpos($desc,$w);
$desc = str_replace($w,"<span style='font-weight: bold;'>".substr($desc,strpos($desc,$w),strlen($w))."</span>",$desc);
}
$i++;
}
$max = 0;
if(sizeof($positions) > 0)
{
foreach($positions as $j)
{
if($max < 4)
{
$i = $j -16;
if($i < 0)
{
$i = 0;
}
$toreturn .= substr($desc,$i,80);
$toreturn .= " ...";
$max++;
}
}
}
else
{
$descs = explode(" ",$desc);
for($i=0; $i < $max_number_words; $i++)
{
$toreturn .= $descs[$i]." ";
}
}
return $toreturn;
}

Print Array if Condition Exists

I'm working on a printing a baseball team lineup, via php. I want to print a place holder for a missing Player 6 (or any missing position)
So if Player 1 -> Player 5 is OK print, NO Player #6 print place holder, Player 7 -> Player 9 is OK print. I tried to simplify the code. I have tried solving this every which way but I keep getting stuck.
CODE:
$rot = array();
$pos = array();
$jn = array();
$x = 1;
// loads up the arrays from the db
while ( $rot[$x], $pos[$x], $jn[$x])= $r->fetch_row() ) {
$x++;
}
// counts the actual number of players in linuep
// used for validation and error display
$num_players = mysqli_num_rows($r);
// controls the lineup position
for ($i = 1; $i <= 15; $i++){
if($rot[$i] == $i) {
//prints player
$lineup .= "<div data-fp='" . $pos[$i] . "'>" .$jn[$i]. "</div>";
} else {
// prints place holder
$text = "This Position needs to be filled before the next game.";
$lineup .= "<div id='pid' data-rel='".$text."' data-fp='' data-pid='' data-jn='' title=''>x</div>";
}
}
I also tried this to iterate through the array rot[] to find the matching position and print the line but it actually prints the holder repeatedly.
// controls the lineup position
for ($x = 1; $x <= 15; $x++){
for ($i = 1; $i <= ($num_players+1); $i++) {
if ($x == $i) {
//prints player
$lineup .= "<div data-fp='" . $pos[$i] . "'>" .$jn[$i]. "</div>";
} else {
// prints place holder
$text = "This Position needs to be filled before the next game.";
$lineup .= "<div id='pid' data-rel='".$text."' data-fp='' data-pid='' data-jn='' title=''>x</div>";
}
}
}
What about:
# index all players by position while taking them from the database
$players = array();
while ( $row = $r->fetch_row() ) {
list($rot, $pos, $jn) = $row;
$players[$pos] = compact(array('rot', $pos, $jn);
}
...
# line-up players
for ($pos = 1; $pos <= 15; $pos++)
{
$playerExists = isset($players[$pos]);
if ($playerExists)
{
# do this ...
}
else
{
# do that ...
}
}
I think you are creating an array where all numerical elements are filled (i.e. you'll always have a 1 thru 15) and your mistake is in the
if($rot[$i] == $i) {
When populating the arrays from the database, add this line:
$playertoid = array_flip($pos); # pos is the player number array?
i.e.
while ( ($rot[$x], $pos[$x], $jn[$x])= $r->fetch_row() ) {
$x++;
}
$playertoid = array_flip($pos);
Now you've created a reverse lookup table where the index is the player number.
Replace the
if($rot[$i] == $i) {
line with:
if (isset($playertoid[$i])) {

Categories