检查字符串的字符是否包含在LINQ

时间:2016-12-10 15:02:05

标签: c# string linq

我正在使用C#在命令行中制作拼字游戏。玩家必须输入一些单词,如下面的列表:

| Word   | Points |
| ------ | ------ |
| some   | 6      |
| first  | 8      |
| potsie | 8      |
| day    | 7      |
| could  | 8      |
| postie | 8      |
| from   | 9      |
| have   | 10     |
| back   | 12     |
| this   | 7      |

玩家得到的字母是:

sopitez

此值为字符串。我会检查字母中是否包含字母。为此,我尝试了这段代码:

String highst = (from word
                 in words 
                 where word.Contains(letters)
                 orderby points descending
                 select word).First();

但它不起作用我会怎么做。此代码不会选择任何单词。我知道原因,因为sopitez不包含任何单词。

现在我的问题是有一种方法可以检查字符串letters中包含的字符是否包含在字符上的字母whitout循环中。

注意:解决方案中每个字母最多只能使用一次。

如果我计算结果,则必须为potsiepostie(我必须为此编写逻辑)

P.S。:我正在玩这个游戏:www.codingame.com/ide/puzzle/scrabble

3 个答案:

答案 0 :(得分:3)

这根本不具备高性能,但至少它会起作用。请注意,我只是为了简单而使用了字典(我也不明白为什么你会重复像“potie”这样的词,我从未玩过拼字游戏)。你可以像如果您遵循此代码,请使用元组列表

编辑:我根据OP的新评论

更改了此内容
using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {

        var letters = new HashSet<char>("sopitez");

        var wordsMap = new Dictionary<string, int>()
        {
            {"some", 6}, {"first", 8}, {"potsie", 8}, {"postie", 8}, {"day", 7},
            {"could", 8}, {"from", 9}, {"have", 10}, {"back", 12},
            {"this", 7}
        };

        var highest = wordsMap
            .Select(kvp => {
                var word = kvp.Key;
                var points = kvp.Value;
                var matchCount = kvp.Key.Sum(c => letters.Contains(c) ? 1 : 0);
                return new {
                    Word = word,
                    Points = points,
                    MatchCount = matchCount,
                    FullMatch = matchCount == word.Length,
                    EstimatedScore = points * matchCount /(double) word.Length // This can vary... it's just my guess for an "Estiamted score"
                };
            })
            .OrderByDescending(x => x.FullMatch)
            .ThenByDescending(x => x.EstimatedScore);


        foreach (var anon in highest)
        {
            Console.WriteLine("{0}", anon);
        }       

    }
}

答案 1 :(得分:1)

这里的问题是Contains检查一个字符串是否包含另一个字符串;它不会检查它是否包含所有这些字符。 您需要使用HashSet<char>替换字典中的每个字符串,并执行IsSubsetIsSuperset等集合比较,以确定字母是否匹配。

以下是您正在做的事情:

string a= "Hello";
string b= "elHlo";
bool doesContain = b.Contains(a); //This returns false

以下是您需要做的事情:

var setA = new HashSet<char>(a);
var setB = new HashSet<char>(b);    
bool isSubset = a.IsSubsetOf(b); //This returns true

<击>的更新 实际上,这是错误的,因为sets删除了重复的元素。但基本上你是在滥用Contains。你需要一些更复杂的序列比较,可以允许重复的字母。

<强> UPDATE2 你需要这个用于单词/字母比较:

//Compares counts of each letter in word and tiles
bool WordCanBeMadeFromLetters(string word, string tileLetters) {

    var tileLetterCounts = GetLetterCounts(tileLetters);
    var wordLetterCounts = GetLetterCounts(word);

    return wordLetterCounts.All(letter =>
        tileLetterCounts.ContainsKey(letter.Key)
        && tileLetterCounts[letter.Key] >= letter.Value);
}

//Gets dictionary of letter/# of letter in word
Dictionary<char, int> GetLetterCounts(string word){
    return word
        .GroupBy(c => c)
        .ToDictionary(
            grp => grp.Key,
            grp => grp.Count());
}

所以你原来的例子看起来像这样:

String highst = (from word
             in words 
             where WordCanBeMadeFromLetters(word, letters)
             orderby points descending
             select word).First();

答案 2 :(得分:1)

由于字母可以重复,我认为你需要这样的东西(当然这不是很有效,但纯粹的LINQ):

var letters = "sopitezwss";

var words = new Dictionary<string, int>() {
    {"some", 6}, {"first", 8}, {"potsie", 8}, {"day", 7},
    {"could", 8}, {"from", 9}, {"have", 10}, {"back", 12},
    {"this", 7}, {"postie", 8}, {"swiss", 15}
};

var highest = (from word
    in words
    where word.Key.GroupBy(c => c).All(c => letters.Count(l => l == c.Key) >= c.Count())
    orderby word.Value descending
    select word);