C# 字典查找我们想要包含在字符串中的键的位置
我有一本C# 字典查找我们想要包含在字符串中的键的位置,c#,linq,dictionary,C#,Linq,Dictionary,我有一本字典,里面有钥匙,例如 "Car" "Card Payment" 我有一个字符串description,例如“向特易购刷卡”,我想在字典中找到与该字符串对应的项目 我试过这个: var category = dictionary.SingleOrDefault(p => description.ToLowerInvariant().Contains(p.Key)).Value; 目前,这会导致字典中同时返回“汽车”和“卡付款”,并且我的代码会因为我的SingleOrDefaul
字典
,里面有钥匙,例如
"Car"
"Card Payment"
我有一个字符串description
,例如“向特易购刷卡”,我想在字典中找到与该字符串对应的项目
我试过这个:
var category = dictionary.SingleOrDefault(p => description.ToLowerInvariant().Contains(p.Key)).Value;
目前,这会导致字典中同时返回“汽车”和“卡付款”,并且我的代码会因为我的SingleOrDefault
而崩溃
我怎样才能实现我想要的?我考虑过在空格中为键加前缀和后缀,但是我必须对描述做同样的事情——我认为这会起作用,但有点脏。还有更好的办法吗?我不反对将字典更改为其他类型,只要性能不会受到太多影响
上述示例所需的结果:仅获得“卡付款”您可以尝试在您的
where
条件之后使用linqOrderByDescending
和Take
。查找最匹配的单词值
var category = dictionary
.Where(p => description.ToLowerInvariant().Contains(p.Key.ToLowerInvariant()))
.OrderByDescending(x => x.Key.Length)
.Take(1);
我会使用
List
来包含密钥,因为没有任何理由需要使用key
和value
集合
List<string> keys = new List<string>();
keys.Add("Car");
keys.Add("Card Payment");
string description = "Card payment to tesco";
var category = keys
.Where(p => description.ToLowerInvariant().Contains(p.ToLowerInvariant()))
.OrderByDescending(x => x.Length)
.Take(1)
.FirstOrDefault();
List key=new List();
钥匙。添加(“汽车”);
密钥。添加(“卡支付”);
string description=“向乐购刷卡”;
变量类别=键
.Where(p=>description.ToLowerInvariant().Contains(p.ToLowerInvariant()))
.OrderByDescending(x=>x.Length)
.采取(1)
.FirstOrDefault();
注意
OrderBy
关键字值length desc可以确定哪个关键字与单词值最匹配。您正在滥用字典。通过扫描键,您不会从字典中获得性能增益。更糟糕的是,在这种情况下,一个简单的列表会更快。如果您通过键查找值,则字典将接近恒定时间访问(O(1)
)
var category = dictionary
.Where(p => description.ToLowerInvariant().Contains(p.Key.ToLowerInvariant()))
.OrderByDescending(x => x.Key.Length)
.Take(1);
if (dictionary.TryGetValue(key, out var value)) { ...
要想利用这一优势,你需要一种更微妙的方法。主要的困难是,有时键可能由多个单词组成。因此,我建议采用两级方法,第一级存储单字键,第二级存储合成键和值
示例:要存储的键值对:
["car"]: categoryA
["card payment"]: categoryB
["payment"]: categoryC
我们建立了一个字典
var dictionary = new Dictionary<string, List<KeyValuePair<string, TValue>>> {
["car"] = new List<KeyValuePair<string, TValue>> {
new KeyValuePair("car", categoryA)
},
["card"] = new List<KeyValuePair<string, TValue>> {
new KeyValuePair("card payment", categoryB)
},
["payment"] = new List<KeyValuePair<string, TValue>> {
new KeyValuePair("card payment", categoryB),
new KeyValuePair("payment", categoryC)
}
};
var字典=新字典{
[“汽车”]=新列表{
新的KeyValuePair(“汽车”,类别)
},
[“卡片”]=新列表{
新的KeyValuePair(“卡支付”,类别B)
},
[“付款”]=新列表{
新的KeyValuePair(“卡支付”,类别b),
新的KeyValuePair(“付款”,类别C)
}
};
当然,在现实中,我们会使用一种算法来实现这一点。但这里的重点是展示结构。如您所见,主键“付款”
的第三个条目包含两个条目:一个用于“卡付款”
,另一个用于“付款”
用于添加值的算法如下所示:
列表中
SelectMany
将此列表展平为单个list
list
键和System.Text.RegularExpressions
找到所需的键。试试看
string description = "Card payment to tesco";
List<string> keys = new List<string> {
{"Car" }, {"Card Payment" }
};
string desc = description.ToLowerInvariant( );
string pattern = @"([{0}]+) (\S+)";
var resp = keys.FirstOrDefault( a => {
var regx = new Regex( string.Format( pattern, a.ToLowerInvariant( ) ) );
return regx.Match( desc ).Success;
} );
string description=“向乐购刷卡”;
列表键=新列表{
{“汽车”},{“卡付款”}
};
string desc=description.ToLowerInvariant();
字符串模式=@“([{0}]+)(\S+);
var resp=keys.FirstOrDefault(a=>{
var regx=newregex(string.Format(pattern,a.ToLowerInvariant());
返回regx.Match(desc.Success);
} );
检查这里您的预期结果是什么?只获得
“卡付款”
?@D-Shih是的,没错为什么不使用FirstOrDefault()
而不是SingleOrDefault()
?@Rick好的,我知道你可以试试我的答案:)我应该解释一下,我的值中有一个对象,以后我会使用匹配的对象。我最初使用了一个列表
,性能非常差。我基本上使用了你的答案,但在查询之前我先订购了字典。这很有魅力。