0

php: sort and count instances of words in a given string

In this article, I have know how to count instances of words in a given string and sort by frequency. Now I want make a further work, match the result words into anther array ($keywords), then only get the top 5 words. But I do not know how to do that, open a question. thanks.

$txt = <<<EOT
The 2013 Monaco Grand Prix (formally known as the Grand Prix de Monaco 2013) was a Formula One motor race that took place on 26 May 2013 at the Circuit de Monaco, a street circuit that runs through the principality of Monaco. The race was won by Nico Rosberg for Mercedes AMG Petronas, repeating the feat of his father Keke Rosberg in the 1983 race. The race was the sixth round of the 2013 season, and marked the seventy-second time the Monaco Grand Prix has been held. Rosberg had started the race from pole.
Background
Mercedes protest
Just before the race, Red Bull and Ferrari filed an official protest against Mercedes, having learned on the night before the race of a three-day tyre test undertaken by Pirelli at the venue of the last grand prix using Mercedes' car driven by both Hamilton and Rosberg. They claimed this violated the rule against in-season testing and gave Mercedes a competitive advantage in both the Monaco race and the next race, which would both be using the tyre that was tested (with Pirelli having been criticised following some tyre failures earlier in the season, the tests had been conducted on an improved design planned to be introduced two races after Monaco). Mercedes stated the FIA had approved the test. Pirelli cited their contract with the FIA which allows limited testing, but Red Bull and Ferrari argued this must only be with a car at least two years old. It was the second test conducted by Pirelli in the season, the first having been between race 4 and 5, but using a 2011 Ferrari car.[4]
Tyres
Tyre supplier Pirelli brought its yellow-banded soft compound tyre as the harder "prime" tyre and the red-banded super-soft compound tyre as the softer "option" tyre, just as they did the previous two years. It was the second time in the season that the super-soft compound was used at a race weekend, as was the case with the soft tyre compound.
EOT;

$words = array_count_values(str_word_count($txt, 1));
arsort($words);
var_dump($words);

$keywords = array("Monaco","Prix","2013","season","Formula","race","motor","street","Ferrari","Mercedes","Hamilton","Rosberg","Tyre"); 
//var_dump($words) which should match in $keywords array, then get top 5 words.
Community
  • 1
  • 1
fish man
  • 2,666
  • 21
  • 54
  • 94
  • Have you seen [this](http://stackoverflow.com/questions/16543617/php-how-to-display-the-5-most-reccurent-words-in-a-list) ? You just have to filter using the keywords – Jacopofar May 30 '13 at 08:58
  • Huh, top 5 ? Isn't [`array_slice()`](http://uk.php.net/manual/en/function.array-slice.php) what you're looking for ? – HamZa May 30 '13 at 08:58

1 Answers1

1

You already have $words as an associative array, indexed by the word and with the count as the value, so we use array_flip() to make your $keywords array an associative array indexed by word as well. Then we can use array_intersect_key() to return only those entries from $words that have a matching index entry in our flipped $keywords array.

This gives a resulting $matchWords array, still keyed by the word, but containing only those entries from the original $words array that match $keywords; and still sorted by frequency.

We then simply use array_slice() to extract the first 5 entries from that array.

$matchWords = array_intersect_key(
    $words,
    array_flip($keywords)
);

$matchWords = array_slice($matchWords, 0, 5);
var_dump($matchWords);

gives

array(5) {
  'race' =>
  int(11)
  'Monaco' =>
  int(7)
  'Mercedes' =>
  int(5)
  'Rosberg' =>
  int(4)
  'season' =>
  int(4)
}

Caveat: You could have problems with case-sensitivity. "Race" !== "race", so the $words = array_count_values(str_word_count($txt, 1)); line will treat these as two different words.

Mark Baker
  • 209,507
  • 32
  • 346
  • 385