我有一个字符串列表,其中每个项目都是描述技能的自由文本,所以看起来有点像这样:
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)。
感谢。
答案 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));