搜索字符串数组中包含的字典键

时间:2017-05-30 20:26:17

标签: c# linq dictionary

我有一个字符串列表,其中每个项目都是描述技能的自由文本,所以看起来有点像这样:

List<string> list = new List<string> {"very good right now", "pretty good",
 "convinced me that is good", "pretty medium", "just medium" .....}

我想保留这些免费文本的用户分数。所以现在,我使用条件:

foreach (var item in list)
        {
            if (item.Contains("good"))
            {
                score += 2.5;
                Console.WriteLine("good skill, score+= 2.5, is now {0}", score);
            }
            else if (item.Contains(low"))
            {
                score += 1.0;
                Console.WriteLine("low skill, score+= 1.0, is now {0}", score);
            }

        }

假设我想要使用字典进行分数映射,例如:

Dictionary<string, double> dic = new Dictionary<string, double>
{ { "good", 2.5 }, { "low", 1.0 }};

在字典值和字符串列表之间交叉的好方法是什么?我现在看到它的方式是做一个嵌套循环:

foreach (var item in list)
        {
            foreach (var key in dic.Keys)
                if (item.Contains(key))
                    score += dic[key];
        }

但我确信有更好的方法。最好更快,更愉快(LINQ)。

感谢。

4 个答案:

答案 0 :(得分:2)

var scores = from item in list
             from word in item.Split()
             join kvp in dic on word equals kvp.Key
             select kvp.Value;

var totalScore = scores.Sum();

注意:您当前的解决方案会检查列表中的项目是否包含字典中的键。但即使字典中的键是项目中某个单词的一部分,它也会返回true。例如。 "follow the rabbit"包含"low"。将项目拆分为单词可以解决此问题。

LINQ join也在内部使用散列集来搜索第二个序列中的第一个序列项。当你枚举字典的所有条目时,这会给你O(1)查找速度而不是O(N)。

答案 1 :(得分:2)

如果您的代码找到包含单词“good”的 N 技能字符串,那么它会追加得分2.5 N 次。

因此,您只需计算包含字典工作的技能字符串,并将相应分数的值相乘。

var scores = from pair in dic
             let word = pair.Key
             let score = pair.Value
             let count = list.Count(x => x.Contains(word))
             select score * count;

var totalScore = scores.Sum();

答案 2 :(得分:1)

它真的不快,但你可以使用LINQ:

chpl_taskID_t

请注意,如果字符串匹配两个键,您的示例循环将会触及2个不同的键,我将其保留在我的解决方案中。

答案 3 :(得分:0)

嗯,你并没有真正使用Dictionary作为字典,所以我们可以用一个新类来简化这一点:

class TermValue
{
    public string Term { get; set; }
    public double Value { get; set; }

    public TermValue(string t, double v)
    {
        Term = t;
        Value = v;
    }
}

有了这个,我们可以更直接一点:

void Main()
{
    var dic = new TermValue[] { new TermValue("good", 2.5), new TermValue("low", 1.0)};


    List<string> list = new List<string> {"very good right now", "pretty good",
 "convinced me that is good", "pretty medium", "just medium" };

    double score = 0.0;
    foreach (var item in list)
    {
        var entry = dic.FirstOrDefault(d =>item.Contains(d.Term));
        if (entry != null)
            score += entry.Value;
    }
}

从这里开始,我们可以稍微玩一下(这个编译后的代码可能与上面相同)

    double score = 0.0;
    foreach (var item in list)
    {
        score += dic.FirstOrDefault(d =>item.Contains(d.Term))?.Value ?? 0.0;
    }

然后,(在紫色的那个词中),我们可以发疯:

double score = list.Aggregate(0.0, 
     (scre, item) =>scre + (dic.FirstOrDefault(d => item.Contains(d.Term))?.Value ?? 0.0));