Jump to content

Archived

This topic is now archived and is closed to further replies.

litebearer

Searching an array for multiple keywords

Recommended Posts

Evening, all...

I can't seem to get my thoughts properly wrapped around this problem.

Scenario:

Searching an array of data for matches to keywords. Create a new array from the matches.

01. From 1 to 3 keywords possible. Match must have ALL keywords.

02. Case insensitive

03. $needle1, $needle2 and $needle3 represent the possible keywords

04. $old_haystack represents an element from the original array

05. $haystack represents lowercase version of $old_haystack

06. must be compatible with PHP versions 3, 4 and 5

I came up with this sledge-hammer approach, looping through all of elements of the original array and runing this function on each element.

However, I am sure there is a more elegant, refined and effective approach, but what is it?

[code]
<?PHP
function validate_words($needle1, $needle2, $needle3, $old_haystack) {
$haystack = strtolower($old_haystack);
$new_element = "";
$kwl[0] = strlen(trim($needle1);
$kwl[1] = strlen(trim($needle2);
$kwl[2] = strlen(trim($needle3);
$add_element = 0;

if(($kwl[0]>0) AND ($kwl[1]>0) AND ($kwl[2]>0) AND (substr_count($haystack, $needle1)>0) AND (substr_count($haystack, $needle2)>0) AND (substr_count($haystack, $needle3)>0)) {
// add element to new array
return 1;
}

if(($kwl[0]>0) AND ($kwl[1]>0) AND ($kwl[2]<1) AND (substr_count($haystack, $needle1)>0)  AND (substr_count($haystack, $needle2)>0)){
// add element to new array
return 1;
}

if(($kwl[0]>0) AND ($kwl[1]<1) AND ($kwl[2]>0) AND (substr_count($haystack, $needle1)>0) AND (substr_count($haystack, $needle3)>0)) {
// add element to new array
return 1;
}

if(($kwl[0]>0) AND ($kwl[1]<1) AND ($kwl[2]<1) AND (substr_count($haystack, $needle1)>0)) {
// add element to new array
return 1;
}

if(($kwl[0]<1) AND ($kwl[1]>0) AND ($kwl[2]>0) AND (substr_count($haystack, $needle2)>0) AND (substr_count($haystack, $needle3)>0)) {
// add element to new array
return 1;
}

if(($kwl[0]><1) AND ($kwl[1]>0) AND ($kwl[2]<1) AND (substr_count($haystack, $needle2)>0)) {
// add element to new array
return 1;
}

if(($kwl[0]<1)  AND ($kwl[1]<1) AND ($kwl[2]>0) AND (substr_count($haystack, $needle3)>0)) {
// add element to new array
return 1;
}
return 0;
}

?>
[/code]

Thanks,

Lite...

Share this post


Link to post
Share on other sites
im having trouble understanding exactly what you're trying to do.

you use substr_count, but i thought $haystack was an array.

it might just be easier to place your needles in one array and your haystack in another and loop though both - again, i dont understand what you are doing. can you explain a little bit more?

Share this post


Link to post
Share on other sites
Hmmm, ok, a little more definition...

First, I know that using mysql would simplify things; however, for various reasons, I am using a flatfile for this particular project.

each line in the file represents a 'record'

each record has several 'fields'

user desires to search the file for all records that contain certain keywords

user can use either 1, 2 or 3 keywords.

user can select that either ALL or ANY of the keywords are in a record

Matching using ANY is no brainer

The code I previously posted will, in the end, accomplish the task.

My basic question was/is:  Is there a more effective, simpler method of reaching the same end result

Not sure if that makes it any clearer.

Thanks,

Lite...

Share this post


Link to post
Share on other sites
try something like this:

[code]<?php
// define the needles
$needle1 = 'one';
$needle2 = 'two';
$needle3 = 'three';

// map a function to all levels of an array
function deep_map($function, $val)
{
if (is_array($val))
{
$return_arr = array();
foreach ($val AS $k => $v)
$return_arr["$k"] = deep_map($function, $val["$k"]);
return $return_arr;
}
else
{
$command = "return (".$function."(\$val));";
return eval($command);
}
}

// the function to see if all the set needles match the element
function check_for_needles($haystack)
{
  // check for needle1, but only if it's set
  if (isset($GLOBALS['needle1']))
  {
    $results[] = (stristr($haystack, $GLOBALS['needle1']) !== FALSE) ? TRUE : FALSE;
  }

  // check for needle2, but only if it's set
  if (isset($GLOBALS['needle2']))
  {
    $results[] = (stristr($haystack, $GLOBALS['needle2']) !== FALSE) ? TRUE : FALSE;
  }

  // check for needle3, but only if it's set
  if (isset($GLOBALS['needle3']))
  {
    $results[] = (stristr($haystack, $GLOBALS['needle3']) !== FALSE) ? TRUE : FALSE;
  }

  // check if all set needles matched - return FALSE if they didn't, the element if they did
  if (in_array(FALSE, $results))
    return FALSE;
  else
    return $element;
}

// run the function on your array haystack (can be multi-leveled)
$matches = deep_map('check_for_needles', $haystack_array);

// strip out the un-matching ones
$matches = array_diff($matches, array(FALSE));

// $matches will now contain all the matching elements, keys intact, at all levels
?>[/code]

may not be anymore elegant, but it might be easier to debug.  the deep_map() is a function i made based on php.net entries, and will map the results of any defined function run on every element to an array with the same structure as the original (key => returned value for that element).  keep this one handy, it helps in a LOT of applications.

hth.

[b]EDIT:  just noticed you said they should be able to select whether ANY or ALL are matched.  this can be adjusted by changing the if() condition in check_for_needles() to suit: checking whether there are any FALSEs vs. three FALSEs.[/b]

Share this post


Link to post
Share on other sites

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.