Order array of sentences by an array containing words / searchterms - php

I have an array of sentences that I retrieve from an MYSQL database based on an array of words:
$queryTitles = '
SELECT title
FROM `#__items`
WHERE `title` REGEXP "'.$search.'" AND `published`=1';
Where $search contains the REGEXP:
foreach ($searchword as $key => $value) {
if ($key === array_key_last($searchword)) {
$search .= '' . $db->escape( $value, true ) . '';
break;
}
$search = '' . $db->escape( $value, true ) . '|';
}
Now I get this list of titles back which contains the words in the $search words. But I'd like to order these list of titles based on the amounts of words found in the array.. But I'm not sure how to do that.
Maybe with usort?
usort($dataCat, function ($a, $b) {
$countA=0;
$countB=0;
foreach ($searchword as $value) {
if(checkIfContains($a, $value )){
$countA++;
}
if(checkIfContains($a, $value )){
$countB++;
}
}
if ($countA == $countB) {
return 0;
}
return ($countA < $countB) ? -1 : 1;
});
But this doesn't work... Anyone know what I am doing wrong?

Related

How to get the values only if all the keys have matched?

I want to make a method that returns keys and values. But only if the keys include the following string "_1" and "__last".
If only one matches then exit the function, only if the two string are included in the key, return the key with the value for a weather.
$infoList = array("_key_1"=>array("time"=>9, "day"=>"Tuesday", "weather"=>"sunny",
"humidity"=>"80%"),
"_key_2"=>array("time"=>5, "day"=>"Tuesday", "weather"=>"cloudy"),
"_key__last"=>array("time"=>3, "day"=>"Sunday", "weather"=>"rainy"))
public function getData() {
$list = array();
foreach($infoList as $key){
if(preg_match('/(_key)_(_1)/', $key) && preg_match('/(_key)_(__last)/', $key) == TRUE){
$list[$key] = $list[$key]["weather"]
}
}
return $list
}
You are making your life so much more difficult that it need be, use str_contains() its easier than building complex REGEX's and getting very confused by the look of it :)
I also fixed a number of other mistakes, such as the foreach that was not going to work, so check all the code.
It is also better to pass data to a function/method otherwise you get into scoping issues!
$infoList = array("_key_1"=>array("time"=>9, "day"=>"Tuesday", "weather"=>"sunny", "humidity"=>"80%"),
"_key_2"=>array("time"=>5, "day"=>"Tuesday", "weather"=>"cloudy"),
"_key__last"=>array("time"=>3, "day"=>"Sunday", "weather"=>"rainy"));
function getData(Array $infoList) {
$list = [];
$found = 0;
foreach($infoList as $key => $val) {
if( str_contains($key, '_1') || str_contains($key, '__last') ) {
$list[$key] = $val["weather"];
$found++;
}
}
if ( $found >= 2 ) {
return $list;
} else {
return false;
}
}
$res = getData($infoList);
if ( $res !== false ){
print_r($res);
} else {
echo 'Not Found';
}
RESULTS
Array
(
[_key_1] => sunny
[_key__last] => rainy
)
If you want to stick with RegEx, you can use positive lookaheads, the same way you check for passwords characters :
<?php
$pattern = '/^(?=.*_1)(?=.*_last).*$/';
$shouldMatch = [
'_1_last',
'foo_1bar_lasthello',
'_last_1',
'foo_lastbar_1hello'
];
echo 'next ones should match : ' . PHP_EOL;
foreach ($shouldMatch as $item)
{
if (preg_match($pattern, $item))
echo $item . PHP_EOL;
}
$shouldNOTMatch = [
'_2_first',
'bar_lasthello',
'foo_las_1hello'
];
echo 'next ones should NOT match : ' . PHP_EOL;
foreach ($shouldNOTMatch as $item)
{
// v------------ check
if (!preg_match($pattern, $item))
echo $item . PHP_EOL;
}
Output :
next ones should match :
_1_last
foo_1bar_lasthello
_last_1
foo_lastbar_1hello
next ones should NOT match :
_2_first
bar_lasthello
foo_las_1hello

PHP get possible string combination of given array which match with given string

I have an array which contains bunch of strings, and I would like to find all of the possible combinations no matter how it's being sorted that match with given string/word.
$dictionary = ['flow', 'stack', 'stackover', 'over', 'code'];
input: stackoverflow
output:
#1 -> ['stack', 'over', 'flow']
#2 -> ['stackover', 'flow']
What I've tried is, I need to exclude the array's element which doesn't contain in an input string, then tried to match every single merged element with it but I'm not sure and get stuck with this. Can anyone help me to figure the way out of this? thank you in advance, here are my code so far
<?php
$dict = ['flow', 'stack', 'stackover', 'over', 'code'];
$word = 'stackoverflow';
$dictHas = [];
foreach ($dict as $w) {
if (strpos($word, $w) !== false) {
$dictHas[] = $w;
}
}
$result = [];
foreach ($dictHas as $el) {
foreach ($dictHas as $wo) {
$merge = $el . $wo;
if ($merge == $word) {
} elseif ((strpos($word, $merge) !== false) {
}
}
}
print_r($result);
For problems like this you want to use backtracking
function splitString($string, $dict)
{
$result = [];
//if the string is already empty return empty array
if (empty($string)) {
return $result;
}
foreach ($dict as $idx => $term) {
if (strpos($string, $term) === 0) {
//if the term is at the start of string
//get the rest of string
$substr = substr($string, strlen($term));
//if all of string has been processed return only current term
if (empty($substr)) {
return [[$term]];
}
//get the dictionary without used term
$subDict = $dict;
unset($subDict[$idx]);
//get results of splitting the rest of string
$sub = splitString($substr, $subDict);
//merge them with current term
if (!empty($sub)) {
foreach ($sub as $subResult) {
$result[] = array_merge([$term], $subResult);
}
}
}
}
return $result;
}
$input = "stackoverflow";
$dict = ['flow', 'stack', 'stackover', 'over', 'code'];
$output = splitString($input, $dict);

PHP: Seeking efficient structure to loop through arrays for match

I have multiple arrays of strings and I'm trying to figure out an efficient way to loop through them for a match and if a match is found, leave the loop. For each array I'm already using a loop to check for matches. There ought to be a better way to do this than just to repeat the inner loop in code for each and every array but I can't figure out how to do it.
Here is my code. It only shows 3 arrays but I'd like to eventually expand this to many more arrays so the code will become more and more inefficient.
$query = $_Request['q'];//query from Internet
$arrayMovies = array("La Dolce Vita","East of Eden","North by Northwest");
$arrayDirectors = array("Fellini","Ray","Hitchcock");
$arrayActors = array("Giancarlo","James","Jimmy");
$match = "";
$type = "";
$phrases = $arrayMovies;
foreach($phrases as $phrase)
{
if(preg_match("/" . $phrase . "/i", $query))
{
$match = $phrase;
$type = "movie";
}
}
//repeat for next array
$phrases = $arrayDirectors;
foreach($phrases as $phrase)
{
if(preg_match("/" . $phrase . "/i", $query))
{
$match = $phrase;
$type = "director";
}
}
//repeat for next array
$phrases = $arrayActors;
foreach($phrases as $phrase)
{
if(preg_match("/" . $phrase . "/i", $query))
{
$match = $phrase;
$type = "actor";
}
}
if ($match!="") {
//DO SOMETHING
}
Is there a way to loop through the arrays and the first time we find a match leave the loop and do something with the match?
Two examples here. You could return early using a function, or breakout a loop. Note both methods will short-circuit after the first match.
<?php
$arrayDirectors = array("Fellini","Ray","Hitchcock");
$arrayMovies = array("La Dolce Vita","East of Eden","North by Northwest");
function keyword_search($keyword, $array) {
foreach($array as $value)
if (preg_match("/\b" . preg_quote($keyword) . "/i", $value))
return true;
}
if(keyword_search('Hitch', $arrayDirectors))
echo 'Search term found in directors.';
Output:
Search term found in directors.
To find which collection you obtain a match:
<?php
foreach(['directors' => &$arrayDirectors, 'movies' => &$arrayMovies] as $collection => $v)
{
if(keyword_search('eden', $v)) {
$matched = $collection;
break;
}
}
echo $matched;
Output:
movies
I've added a word boundary to your regex, otherwise it's easy to match prematurely/or over match IMHO.
But you'll probably want to match multiple titles. In which case you might want to filter your arrays instead:
<?php
$arrayMovies = array("North to Alaska","East of Eden","North by Northwest","Westworld");
function keyword_filter($keyword, $array) {
return array_filter($array, function($value) use ($keyword) {
return preg_match("/\b" . preg_quote($keyword) . "/i", $value);
});
}
var_export(keyword_filter('north', $arrayMovies));
echo "\n";
var_export(keyword_filter('west', $arrayMovies));
Output:
array (
0 => 'North to Alaska',
2 => 'North by Northwest',
)
array (
3 => 'Westworld',
)
You can use array_merge to combine your arrays into a single array. Then you only need to loop through it once. You can use the continue key word to escape the loop when you have found a match.
<?php
$query = 'James';//query from Internet
$arrayMovies = array("La Dolce Vita","East of Eden","North by Northwest");
$arrayDirectors = array("Fellini","Ray","Hitchcock");
$arrayActors = array("Giancarlo","James","Jimmy");
$match = null;
$phrases = array_merge($arrayMovies, $arrayDirectors, $arrayActors);
foreach($phrases as $phrase)
{
if(preg_match("/" . $phrase . "/i", $query))
{
$match = $phrase;
continue;
}
}
if (!empty($match)) {
echo 'Found a match for ' . $match;
}
Alternatively, you don't need to loop through the array. You can use preg_grep to search your array once it is merged. http://php.net/manual/en/function.preg-grep.php

i dont want to display comma after displaying last value

Display comma after displaying last value:
$len = count($boltpatterns);
foreach ($boltpatterns as $key => $boltpattern) {
$st1=$boltpattern['BP'];
$st2='-';
$pos=strpos($st1,$st2);
if($pos === false){
} else {
echo $st1;
if($key != $len - 1) {
echo ',';
}
}
}
You could have simply used array_column() and implode() function.
array_column() lists all your 'BP' keys into one single dimensional array.
implode() converts this single dimensional array $arr into string, separating each entry with a comma.
$arr = array_column($boltpatterns, 'BP');
echo implode(',', $arr);
Just add a new variable that will keep track of how many items you have looped through.
$len = count($boltpatterns);
$count = 1;
foreach ($boltpatterns as $key => $boltpattern) {
$st1=$boltpattern['BP'];
$st2='-';
$pos=strpos($st1,$st2);
if($pos === false){
} else {
echo $st1;
if($count != $len) {
echo ',';
}
}
++$count;
}
You can do this like this,
$valid_data = array();
foreach ($boltpatterns as $key => $boltpattern) {
if ( false !== strpos($boltpattern['BP'],'-') ){
$valid_data[] = $boltpattern['BP'];
}
}
echo implode(", ", $valid_data);
Explanation: Here we collect all the valid date we need to display to a new array. And we use PHP inbuilt function to display them.
Hope this will help you.
$arr = array_column($boltpatterns, 'BP');
echo rtrim(implode(', ', $arr), ', ');
This is an improved version of #object-manipulator's code, with rtrim removing the trailing comma.

Sorting search results array by number of matches?

I'm building a basic search function for my site. Realising that the most useful search displays the page with the most counts of the terms given, I coded the following:
function search()
{
$this->page = preg_replace('/[^\w \"\']/i', '', trim($this->page));
preg_match_all('/"(.[^"]+)"|([\w]+)/i', $this->page, $terms);
$terms=array_unique($terms[0]); // scrub duplicate search terms
$tsql="SELECT reviewSummary, reviewFullText, game.gameName FROM review LEFT JOIN game ON review.gameID = game.gameID ";
$constraint="WHERE";
foreach ($terms as $term)
{
$term=str_replace('"','',$term);
$tsql.=" $constraint (reviewSummary LIKE '%".$term."%' OR reviewFullText LIKE '%".$term."%' OR game.gameName LIKE '%".$term."%')";
$constraint="AND";
}
$tsql .= "AND game.isPublished = 'y'";
$result = $this->sql->db_query($tsql);
if (mysql_num_rows($result)!=0)
{
while($row = mysql_fetch_array($result))
{
$gameName = stripslashes($row['gameName']);
$content = strip_tags($row['reviewFullText']) . ' ' . $row['reviewSummary'];
$counter = 0;
foreach($terms as $term)
{
$term=str_replace('"','',$term);
preg_match_all("/($term)/i", $content, $matches);
foreach($matches[0] as $m)
{
$counter++;
}
}
$found["Games"][$gameName]=$counter;
}
}
print_r($found);
}
Works great. What it doesn't do is order the results in according to which has the most matches. I'm not sure how to sort the resulting array to achieve this, can anyone help?
Take a look at at uasort() which can sort an associative array using a user-defined comparison function. Something like this should do it...
function cmp($a, $b) {
if ($a == $b) {
return 0;
}
return ($a < $b) ? 1 : -1;
}
uasort($found["Games"], 'cmp');

Categories