如何检查是否可以从字母列表中创建单词?

时间:2017-08-02 05:02:00

标签: php arrays string loops words

我有一个字符串$raw="aabbcdfghmnejaachto"和一个数组$word_array=array('cat','rat','goat','total','egg')

我的程序需要检查是否可以使用字符串中的字母来生成数组中的单词。有一个额外的条件;如果单词包含多于一次的字母,则该字母必须至少在字符串中出现相同的次数。

E.g。 egg。有两个g。如果字符串$raw不包含两个g,则无法生成此单词。

这是我的预期结果:

Array([cat]=>'Yes',[rat]=>'No',[goat]=>'Yes',[total]=>'No',[egg]=>'No')

我尝试了以下操作,但它没有输出预期的结果:

$res=array();
$raw="aabbcdfghmnejaachto";
$word_array=array('cat','rat','goat','total','egg');
$raw_array= str_split($raw);
foreach($word_array as $word=>$value)
{
    $word_value= str_split($value);
    foreach($word_value as $w=>$w_value)
    {
        foreach($raw_array as $raw=>$raw_value)
        {
            if(strcmp($w_value,$raw_value)==0)
            {
                $res[$value]='Yes';
            }
            else
            {
                $res[$value]='No';
            }
        }
    }
}
print_r($res);

编辑:最初发布的代码缺少字符串e中的字母$raw,因此egg示例实际上会返回{{1} }}。我已更新问题和所有答案以反映这一点。 - robinCTS

7 个答案:

答案 0 :(得分:9)

  • 您必须遍历$words数组中的每个单词/元素,然后再循环遍历每个单词的每个字符。
  • 在外循环的每次迭代中,将默认结果值设置为Yes
  • 然后你必须迭代当前单词的每个唯一字符。 (array_count_values()
  • 检查单词中当前字符的出现次数是否大于字母串中当前字符的出现次数。

*作为性能优化的问题,在内循环上使用array_count_values()以避免$word中重复字母的任何不必要的迭代。 $count变量保存了必须在if语句中进行两次substr_count()调用。

代码:(Demo

$string = "aabbcdfghmnejaachto";
$words = array('cat','rat','goat','total','egg');
foreach ($words as $word) {  // iterate each word
    $result[$word]='Yes';  // set default result value
    foreach (array_count_values(str_split($word)) as $char=>$count) {  // iterate each unique letter in word
        if ($count > substr_count($string, $char)) {  // compare current char's count vs same char's count in $string
            $result[$word]='No';  // if more of the character in word than available in $string, set No
            break;  // make early exit from inner loop, to avoid unnecessary iterations
        }
    }    
}
var_export($result);

这是输出:

array (
  'cat' => 'Yes',
  'rat' => 'No',
  'goat' => 'Yes',
  'total' => 'No',
  'egg' => 'No',
)

BIG THANKYOU mickmackusa 劫持显着增强了这个答案。

答案 1 :(得分:2)

您的问题是您没有计算$raw数组中每个字符出现的次数,您只需检查每个字中的每个字符,以查看$raw中是否存在该字符。除非你进行某种形式的计数,否则为每个单词复制$raw并删除使用中的字母,否则你将无法做到这一点。

答案 2 :(得分:2)

我已计算字符串中出现的字符数并比较该出现次数!你可以找到这个答案!

$res=array();
$raw="aabbcdfghmnejaachto"; //tgrel -- to make all yes
$res=array();
$word_array=array('cat','rat','goat','total','egg');
$raw_array= str_split($raw);
$count_raw = array_count_values($raw_array);

foreach($word_array as $value)
{
    $word_value= str_split($value);
    $newArray = array_count_values($word_value);
    $res[$value]='yes';
    foreach($newArray as $char=>$number){
        if(!isset($count_raw[$char]) || $count_raw[$char]<$number){
            $res[$value]='No';
            break;
        }
    }
}
print_r($res);

答案 3 :(得分:1)

你的错误很明显,你决定在单个字符测试中是否接受一个单词的值,而它应该基于单词的所有字母,你不需要同时精确数组的键和值,如果只需要它的值 如在

foreach($word_array as $value)

然后我发现使用函数in_array(),使代码更清晰

$res=array();
$raw="aabbcdfghmnejaachto";
$res=array();
$word_array=array('cat','rat','goat','total','egg');
$raw_array= str_split($raw);

foreach($word_array as $value)
{
    $word_value= str_split($value);
    $res[$value]='yes';
    foreach($word_value as $w_value)
    {
        if (!in_array($w_value,$raw_array))
            $res[$value]='No';

    }
}
print_r($res);

答案 4 :(得分:1)

让我们尝试使用w / o循环,但使用闭包:

$raw = "aabbcdfghmnejaachto";
$word_array = ['cat', 'rat', 'goat', 'total', 'egg'];

$result = [];
$map = count_chars($raw, 1);
array_walk(
    $word_array,
    function ($word) use ($map, &$result) {
        $result[$word] = !array_udiff_assoc(
            count_chars($word, 1), $map, function ($i, $j) { return $i > $j; }
        ) ? 'Yes' : 'No';
    }
);
  1. 我们正在构建一个符号地图,在count_chars($raw, 1)的原始字符串中使用,所以它看起来像这样。
  2. $map:

    [
        97 => 4, // "97" is a code for "a"; and "4" - occurrence number.
        98 => 2,
        ...
    ]
    
    1. array_walk会翻译单词并将其中的每一个添加到最终$result中,其中YesNo值来自与地图的比较,这是为一个单词而构建的。

    2. array_udiff_assoc比较两张地图,丢弃那些具有相同关键字的元素和较大的原始地图值(与单词的地图比较)。此外, array_udiff_assoc()返回一个数组,其中包含来自array1的所有值,这些值在任何其他参数中都不存在,因此最后一步是array_udiff_assoc之前的否定操作。

    3. Demo

答案 5 :(得分:0)

试试这个

$res=array();
$word_array=array('cat','rat','goat','total','egg');
$raw="aabbcrdfghmnejaachtol";
foreach($word_array as $word=>$value)
{
    $raw_array= str_split($raw);
    $res[$value]='Yes';
    $word_value= str_split($value);
    foreach($word_value as $w=>$w_value)
    {
        if(!in_array($w_value,$raw_array))
        {
             $res[$value]='No';
        }
        else
        {
            unset($raw_array[array_search($w_value, $raw_array)]);
        }
    }
}

如果使用一次,则不会再允许使用字符。如“total”。

答案 6 :(得分:0)

我们可以查看每个单词的每个字母是否都在给出的字母内,然后在我们去的时候找出字母。

如果找不到信件,下面的功能会短路。

<?php
function can_form_word_from_letters($word, $letters) {
    $letters      = str_split($letters);
    $word_letters = str_split($word);
    foreach($word_letters as $letter) {
        $key = array_search($letter, $letters);
        if($key === false) return;
        unset($letters[$key]); // Letter found, now remove it from letters.
    }
    return true;
}

$letters = "aabbcdfghmnejaachto";
$words   = array('cat','rat','goat','total','egg');

foreach($words as $word) {
    $result[$word] = can_form_word_from_letters($word, $letters) ? 'Yes' : 'No';
}

var_dump($result);

输出:

array (size=5)
  'cat' => string 'Yes' (length=3)
  'rat' => string 'No' (length=2)
  'goat' => string 'Yes' (length=3)
  'total' => string 'No' (length=2)
  'egg' => string 'No' (length=2)