Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 字典查找我们想要包含在字符串中的键的位置_C#_Linq_Dictionary - Fatal编程技术网

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
条件之后使用linq
OrderByDescending
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)
}
};
当然,在现实中,我们会使用一种算法来实现这一点。但这里的重点是展示结构。如您所见,主键
“付款”
的第三个条目包含两个条目:一个用于
“卡付款”
,另一个用于
“付款”

用于添加值的算法如下所示:

  • 将关键字拆分为单个单词
  • 对于每个单词,使用该单词作为主键创建字典条目,并将键值对作为字典值存储在列表中。第二个键是可能由几个单词组成的原始键
  • 可以想象,步骤2要求您测试具有相同主键的条目是否已经存在。如果是,则将新条目添加到现有列表中。否则,使用单个条目创建一个新列表,并将其插入字典

    检索如下所示的条目:

  • 将关键字拆分为单个单词
  • 对于每个单词,使用true检索现有词典条目,从而将词典快速查找(!)到
    列表中
  • 使用
    SelectMany
    将此列表展平为单个
    list
  • 按键长度降序对它们进行排序,并测试描述是否包含键。找到的第一个条目是结果
  • 您还可以将步骤2和步骤3结合起来,直接将单个词典条目的列表条目添加到主列表中。

    这里我使用的是
    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好的,我知道你可以试试我的答案:)我应该解释一下,我的值中有一个对象,以后我会使用匹配的对象。我最初使用了一个
    列表
    ,性能非常差。我基本上使用了你的答案,但在查询之前我先订购了字典。这很有魅力。