...

View Full Version : array_diff only compare array element ONCE



martynball
04-26-2012, 06:14 PM
I'm having a problem here, as I only want the $chars to compare each array element ONCE, and if a match is found then it should be removed...

Because as you can see, both words here will be added to the $con_words array, as the function is using the "e" twice.



<?php
$words = array("mobile", "belief");
$chars = array("m","o","b","i","l","e","h","u","f","h","n","k");

for ($i = 0; $i < count($words); $i++) {
$word_spl = str_split($words[$i]);
$result = array_diff($word_spl, $chars);
if (empty($diff)) {
$con_words[] = $words[$i];
}
}

print_r($con_words);
?>

Fou-Lu
04-26-2012, 06:26 PM
Pull the array_diff the other way as well:


$diff = array_diff($word_spl, $chars);
$chars = array_diff($chars, $word_spl);

I assumed that $result should have been $diff. This will remove any repetition as well though.

martynball
04-26-2012, 06:31 PM
How do I go about checking?



<?php
$words = array("mobile", "belief");
$chars = array("m","o","b","i","l","e","h","u","f","h","n","k");

for ($i = 0; $i < count($words); $i++) {
$word_spl = str_split($words[$i]);

$diff = array_diff($word_spl, $chars);
$chars = array_diff($chars, $word_spl);

if (empty($chars) && empty($diff)) {
$con_words[] = $words[$i];
}
}

print_r($con_words);
?>


I'm guessing like above, then then no words are displayed. But if I just do this:


if (empty($diff)) {
$con_words[] = $words[$i];


Then ONLY "mobile" is displayed, but that just ignores the second check? :S

Fou-Lu
04-26-2012, 06:36 PM
The condition doesn't change. The $chars has been reassigned to remove the characters used in the first array_diff call.

martynball
04-26-2012, 07:03 PM
Ah I see, thanks :)

martynball
04-26-2012, 08:48 PM
Actually, it still doesn't seem to work when looking through a dictionary.

If I enter these characters:


b,a,t,t,e,r,y,g,j,u,b,t


No word is actually found, the word that should be found is "battery". It is in the database:


ID word
6909 battery


If I just stick with the code below, it finds "battery" but also another 42 words as well. Which should not happen. If I add that extra bit of code:


$chars = array_diff($chars, $word_split);


Then no words are found at all.



//Add all characters to Array
while ($g != 13) {
$c_char = mysql_real_escape_string($_GET['char'.$g]); //Current character
if ($c_char) {
$chars[] = $c_char;
}
$g++;
}

//Start fecthing database data
$query = "SELECT * FROM dictionary WHERE LENGTH(word) = ".$length." ORDER BY ranking DESC";
$result = mysql_query($query);

if(!$result) { $return_data = "Error connecting to dictionary!"; }

//Fetch word matching the selected length
while($row = mysql_fetch_array($result))
{
$data = trim($row['word']);
$word_split = str_split($data);

$diff = array_diff($word_split, $chars);
//$chars = array_diff($chars, $word_split);

if (empty($diff)) {
$con_words[] = $data;
}
}


Any ideas? As I have not got a clue.

Fou-Lu
04-26-2012, 10:07 PM
Now you just have me confused. If I do this:


$aChars = array('b','a','t','t','e','r','y','g','j','u','b','t');
$string = "battery";

$aString = str_split($string);
$diff = array_diff($aString, $aChars);
$aChars = array_diff($aChars, $aString);
if (empty($diff))
{
printf("Characters found in %s" . PHP_EOL, $string);
}
print_r($aChars);

Will result in:


Characters found in battery
Array ( [7] => g [8] => j [9] => u )

As I said it will consume all the characters within the strings when calculating the difference. The only remaining characters are g, j and u, and that doesn't really form any possible words. Therefore a call to the empty($diff) will result in a lot of falses to follow unless your word is gju, guj, jgu, jug, ugj, or ujg.

So what exactly is it you are trying to do here? It almost looks like a spell checker. If this is the case you may be better off using a levenshtein and metaphone to find similar words. Both of these can be used when inserting data into the database to create two additional columns to search on, then calculate the word input and select from the database where they match. If the levenshtein and metaphone both match in a single row, that should be the literal input, while you can sort the results remaining by either spells with the same characters (levenshtein) or sounds the same (metaphone).

martynball
04-26-2012, 11:08 PM
Basically, what it should do is search for words which can be made with the given characters, and are a defined length. So far it work's but it's finding too many words as it is using some characters more than once.

Once a character has been used it shouldn't be used again.

Fou-Lu
04-27-2012, 01:01 AM
Okay, then if I got you right you just want to make sure you have enough characters to spell the word?


<?php

function canSpellsWord($sWord, array $aFromChars)
{
$bResult = true;
$aWord = count_chars($sWord, 1);
$aLetters = array_count_values($aFromChars);

$iLetters = count($aWord);
if (count($aFromChars) > 0)
{
while ($bResult && (list($key, $val) = each($aWord)))
{
$c = chr($key);
if (!isset($aLetters[$c]) || $aLetters[$c] < $val)
{
$bResult = false;
}
}
}
else
{
$bResult = false;
}

return $bResult;
}

$words = array("mobile", "belief", "funkei");
$chars = array("m","o","b","i","l","e","h","u","f","h","n","k");

foreach ($words AS $word)
{
printf('$chars can spell word %s? %d' . PHP_EOL, $word, canSpellsWord($word, $chars));
}

martynball
04-27-2012, 02:36 AM
After reading through that code and researching many functions that I have not come across I think that will solve my problem.

I will have another read through tomorrow and try and implant it into my code to see if it does what I want. I don't like using someone elses code until I understand exactly what it does.

I don't see the point in coding something if it's all copy and paste, don't learn anything like that. So before I will use this I need to fully understand it.

martynball
04-27-2012, 04:23 PM
That function will make sure that each char item is only used ONCE, correct?

Fou-Lu
04-27-2012, 04:58 PM
That function will make sure that each char item is only used ONCE, correct?

Correct, but for each word.

martynball
04-27-2012, 05:53 PM
Quick question, this line here function canSpellsWord($sWord, array $aFromChars) , do you need to put "array" in front of the, well array so that it stays an array whilst being passed to the function?

Fou-Lu
04-27-2012, 06:19 PM
No, that only forces it to only accept an array. I wish PHP at least type hint strong for all primitive datatypes, but only array and a class type can be used for the datatype in the signature.

martynball
04-27-2012, 09:01 PM
Hmm, strange.

This should work, but instead blank values are displayed... Roughly about 4000



//Start fecthing database data
$query = "SELECT * FROM dictionary WHERE LENGTH(word) = ".$length." ORDER BY ranking DESC";
$result = mysql_query($query);

if(!$result) { $return_data = "Error connecting to dictionary!"; }

//Fetch word matching the selected length
while($row = mysql_fetch_array($result))
{
$data = trim($row['word']);

$con_words[] = canSpellsWord($data, $chars);
}

Fou-Lu
04-27-2012, 09:08 PM
It doesn't return the word, it returns a boolean. You have to use it as:


if (canSpellsWord($data, $chars))
{
$con_words[] = $data;
}

If they are all blank entries in the array, all matches are false. Make sure $chars exists.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum