0
\$\begingroup\$

I'm using a levenshtein matching algorithm to match a title to a filename (for anime). I either use the main show title for matching or its alternative titles (flexget_titles).

For that I have the following snippet of code.

public function matchFilenameToShow($filename)
{
    $shows = $this->shows->getAll();
    $shortest = -1;
    $clean_name = $this->removeEpisodeNumber($this->cleanFilename($filename));
    foreach ($shows as $show) {
        if (!empty($show->flexget_titles_array)) {
            foreach ($show->flexget_titles_array as $title) {
                // calculate the distance between the input string filename,
                // and the current show name
                $lev = levenshtein(strtolower($clean_name), strtolower($title));
                // if this distance is less than the next found shortest
                // distance, OR if a next shortest distance to the word has not yet been found
                if ($lev <= $shortest || $shortest < 0) {
                    // set the closest match, and shortest distance
                    $matchedShow = $show;
                    $shortest = $lev;
                }
            }
        } else {
            // calculate the distance between the input string filename,
            // and the current show name
            $lev = levenshtein(strtolower($clean_name), strtolower($show->title));
            // if this distance is less than the next found shortest
            // distance, OR if a next shortest distance to the word has not yet been found
            if ($lev <= $shortest || $shortest < 0) {
                // set the closest match, and shortest distance
                $matchedShow = $show;
                $shortest = $lev;
            }
        }
    }
    return $matchedShow;
}

Obviously there is code repetition and I want to refactor this. However I'm not sure how to do it. I have a feeling that I need to extract that levenshtein part to a separate method, but I need to return 2 variables.

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

You can create "fallback" version of nested array in the case when $show->flexget_titles_array is empty and handle it with the same nested foreach loop:

...
foreach ($shows as $show) {
    ($arr = $show->flexget_titles_array) || ($arr = array($show->title));
    foreach ($arr as $title) {
        // calculate the distance between the input string filename,
        // and the current show name
        $lev = levenshtein(strtolower($clean_name), strtolower($title));
        // if this distance is less than the next found shortest
        // distance, OR if a next shortest distance to the word has not yet been found
        if ($lev <= $shortest || $shortest < 0) {
            // set the closest match, and shortest distance
            $matchedShow = $show;
            $shortest = $lev;
        }
    }
}
...
\$\endgroup\$
1
  • \$\begingroup\$ Welcome to CodeReview, hindmost. I hope you enjoy the site. \$\endgroup\$
    – Legato
    Apr 20, 2015 at 15:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.