Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.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# - Fatal编程技术网

C# 如何进行字典反向查找

C# 如何进行字典反向查找,c#,C#,我有一个类型的字典,对于一个特定的情况,我需要进行反向查找。例如,假设我有这个条目,并且我传入“ab”,那么我想返回“SomeString”。 在我开始对字典中的每个条目进行foreach循环之前,我想知道进行反向查找最有效的方法是什么?基本上,您可以使用LINQ像这样获得键,而不必进行任何反向操作: var key = dictionary.FirstOrDefault(x => x.Value == "ab").Key; 如果您真的想撤销词典,可以使用如下扩展方法: public s

我有一个
类型的字典,对于一个特定的情况,我需要进行反向查找。例如,假设我有这个条目
,并且我传入
“ab”
,那么我想返回
“SomeString”

在我开始对字典中的每个条目进行
foreach
循环之前,我想知道进行反向查找最有效的方法是什么?

基本上,您可以使用
LINQ
像这样获得
键,而不必进行任何反向操作:

var key = dictionary.FirstOrDefault(x => x.Value == "ab").Key;
如果您真的想撤销词典,可以使用如下扩展方法:

public static Dictionary<TValue, TKey> Reverse<TKey, TValue>(this IDictionary<TKey, TValue> source)
{
     var dictionary = new Dictionary<TValue, TKey>();
     foreach (var entry in source)
     {
         if(!dictionary.ContainsKey(entry.Value))
             dictionary.Add(entry.Value, entry.Key);
     }
     return dictionary;
} 
var reversedDictionary = dictionary.Reverse();
var key = reversedDictionary["ab"];
注意:如果您有重复的值,则此方法将添加第一个
值,并忽略其他值。

1)键是唯一的,值不是唯一的。对于给定的值,您有一组键

2) 按键查找是
O(log n)
。使用
foreach
或LINQ进行迭代是
O(n)

所以,
选项A:使用LINQ进行迭代,每个请求花费
O(n)
,无需额外内存。

选项B:维护
Dictionary
,为每个请求花费
O(logn)
,使用
O(n)
额外内存。(有两个子选项:在一系列查找之前构建此词典;始终维护它)

使用Linq
ToDictionary
功能:

var reversed = d.ToDictionary(x => x.Value, x => x.Key);
正如在Linqpad中测试的那样,您可以在下面看到它的工作原理:

var d = new Dictionary<int, string>();
d.Add(1,"one");
d.Add(2,"two");
d.Dump(); //prints it out in linq-pad
var reversed = d.ToDictionary(x => x.Value, x => x.Key);
reversed.Dump(); //prints it out in linq-pad
var d=newdictionary();
d、 添加(1,“一”);
d、 添加(2,“两”);
d、 Dump()//在linq pad中打印出来
var反向=d.ToDictionary(x=>x.Value,x=>x.Key);
倒排()//在linq pad中打印出来

使用linq函数进行编辑怎么样:

var reversedDictionary = dictionary.ToDictionary(x => x.Value, x => x.Key);

当字典的实际查找方向(键>值)不受关注时,您可以从头开始在另一个方向构造它。此外,IDictionary(TKey,TValue)的扩展方法也很有用,它可以更容易地为一个值捕获多个键

一个例子 问题:在一组时间单位中,每个时间单位可以被赋予不同的名称。g、 “h”、“hr”、“hrs”、“hour”或“hours”表示时间单位“hour”,我必须为名称或缩写找到合适的时间单位

我的解决方案:(它是VB.net,但应该很容易转换)

导入系统
导入System.Collections.Generic
导入System.Runtime.CompilerServices
公共类计时单位
私有只读\u名称作为字符串
Public Sub New(ByVal name作为字符串,ByVal avgSpan作为TimeSpan)
_name=name
_AvgSpan=AvgSpan
端接头
公共只读属性AvgSpan()作为TimeSpan
Public将函数ToString()重写为字符串
返回\u名称
端函数
末级
公共类时间单位
私有只读项作为新字典(字符串,时间单位)(37,StringComparer.OrdinalIgnoreCase)_
从{{{“n”,“min”,“min”,“minutes”,“minutes”,“minuten”},
新的时间单位(“分钟”,TimeSpan.FromMinutes(1))},
{{“h”,“hr”,“hrs”,“std”,“stunde”,“hour”,“stunden”,“hours”},
新的时间单位(“小时”,TimeSpan.FromHours(1))},
{{“d”,“t”,“day”,“tag”,“days”,“tage”},
新的时间单位(“天”,TimeSpan.FromDays(1))},
{{“m”,“mo”,“月”,“月”,“月”,“单体”},
新的时间单位(“月”,时间跨度FromDays(30.4375))},
{{“q”、“四分之一”、“四分之一”、“四分之一”、“四分之一”},
新的时间单位(“季度”,TimeSpan.FromDays(91.3125))},
{{“y”、“yy”、“yyy”、“yyy”、“j”、“year”、“jahr”、“years”、“jahre”},
新的时间单位(“年”,TimeSpan.FromDays(365.25))}
作为时间单位的公共函数GetBy缩写(ByVal缩写为字符串)
退货项目(缩写)
端函数
末级
公共模块扩展方法
公共子添加(TKey,TValue)(ByVal valItems作为IDictionary(TKey,TValue),ByValKeys作为IEnumerable(TKey,TValue),ByValValValue作为TValue)
对于每个tempKey作为valKeys中的TKey
valItems.Add(临时键、阀门值)
下一个
端接头
端模块
公共模块主
公用分干管()
Dim名称为String=“Jahr”
Console.WriteLine(String.Format)(“{0}”的时间单位是{1}.”,name,(New TimeUnits.getBy缩写(name)))
端接头
端模块

输出:“Jahr”的时间单位为年。

通用
字典
对象的反向查找扩展方法:

“非保证唯一值”扩展:

public static TKey[] ReverseLookup<TKey, TValue>(this Dictionary<TKey, TValue> me, TValue value)
{
    try
    {
        if (me.ContainsValue(value))
            return me.Where(a => a.Value.Equals(value)).Select(b => b.Key).ToArray();
        else
            return null;
    }
    catch
    {
        return null;
    }
}
public static TKey SmartReverseLookup<TKey, TValue>(this Dictionary<TKey, TValue> me, TValue value, TKey DefaultIfEmpty)
{
    try
    {
        if (me.ContainsValue(value))
            return me.First(a => a.Value.Equals(value)).Key;

        return DefaultIfEmpty;
    }
    catch
    {
        return DefaultIfEmpty;
    }
}

使用单键->值字典,foreach循环是从值中获取键的最有效方法。没有内置机制按值获取键。值的LINQ将为O(n)。如果你想要O(1),那么你需要实现两个字典——在第二个字典中,你只需要反转键和值。如果你的字典中有多个具有相同值的元素,你想做什么?@ZombieSheep:在这种特殊情况下不会发生这种情况。可以说是更好的代码,但没有比每个
更有效。这种反转就是O(n)-为什么要执行O(n)以避免和O(n)。要做到这一点,需要一个双向的集合,并将其添加到这两个集合中
Reverse
在{1=>“a”,2=>“a”}上崩溃。
Reverse
是一个可怕的名字,该方法根本没有反转任何东西
Flip
Swap
Switch
更有意义。所有返回物化集合的LINQ方法都被命名为
ToSomething
ToArray
ToList
ToDictionary
ToHashSet
)。我所说的物化是指不延迟。因此,为了跟上惯例,这一个可以被命名为
thettοReverseDictionary
。按键查找字典是O(1)-按hashbucketRemarks on的字面意思是“接近O(1)”。我将更深入地挖掘,并返回我的发现。以下是源代码:有问题的代码位于第248行。所以,看你的速度
public static TKey SmartReverseLookup<TKey, TValue>(this Dictionary<TKey, TValue> me, TValue value, TKey DefaultIfEmpty)
{
    try
    {
        if (me.ContainsValue(value))
            return me.First(a => a.Value.Equals(value)).Key;

        return DefaultIfEmpty;
    }
    catch
    {
        return DefaultIfEmpty;
    }
}
Dictionary<string, int> numsList = new Dictionary<string, int>()
{
    {"Test One", 1}
    {"Test Two", 2}
    {"Test Three", 3}
    {"Test Four", 3}
}

string[] foundKeys;
foundKeys = numsList.ReverseLookup(3);

Console.WriteLine(numsList.SmartReverseLookup(2, "NOT FOUND"));

Console.WriteLine("foundKeys = " + (foundKeys != null ? ("Alive [" + foundKeys.Count() + "]") : "NULL"));

Console.WriteLine(numsList.SmartReverseLookup(4, "!! UNKNOWN !!"));
"Test Two"
"foundKeys = Alive[2]"
"!! UNKNOWN !!"