字典的取值

常用的取值方法有2种:

方法1:先判断是否存在,如果存在再进行取值if(aDictionary.ContainsKey(key))

{

var value = Dictionary[key];

}int value;

aDictionary.TryGetValue(key, out value);

项目中,如果只是要取值,推荐使用TryGetValue来获取。

原因:

方法1中ContainsKey执行了一次方法,Dictionary[key]再次执行了一次方法,整个取值过程调用了2次方法。而方法2的TryGetValue只调用了一次方法。当然并不是调用的方法越多越耗性能,看源码后就能理解。

方法1:

public bool ContainsKey(TKey key) {

return FindEntry(key) >= 0;

}

//Dictionary[key]取值原理

public TValue this[TKey key] {

get {

int i = FindEntry(key);

if (i >= 0) return entries[i].value;

ThrowHelper.ThrowKeyNotFoundException();

return default(TValue);

}

set {

Insert(key, value, false);

}

}

方法2:

public bool TryGetValue(TKey key, out TValue value)

{

if (key == null)

{

ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);

}

lock(_lock)

{

VerifyIntegrity();

return TryGetValueWorker(key, out value);

}

}

private bool TryGetValueWorker(TKey key, out TValue value)

{

int entryIndex = FindEntry(key);

if (entryIndex != -1)

{

Object primary = null;

Object secondary = null;

_entries[entryIndex].depHnd.GetPrimaryAndSecondary(out primary, out secondary);

// Now that we've secured a strong reference to the secondary, must check the primary again

// to ensure it didn't expire (otherwise, we open a ---- where TryGetValue misreports an

// expired key as a live key with a null value.)

if (primary != null)

{

value = (TValue)secondary;

return true;

}

}

value = default(TValue);

return false;

}

通过源码可以看到,这几个方法都获取值都要通过FindEntry(key)来实现

private int FindEntry(TKey key)

{

int hashCode = RuntimeHelpers.GetHashCode(key) & Int32.MaxValue;

for (int entriesIndex = _buckets[hashCode % _buckets.Length]; entriesIndex != -1; entriesIndex = _entries[entriesIndex].next)

{

if (_entries[entriesIndex].hashCode == hashCode && _entries[entriesIndex].depHnd.GetPrimary() == key)

{

return entriesIndex;

}

}

return -1;

}

可以看出通过key来获取HashCode,然后通过equal比对值,字典存储中会给key一个对应的hashcode,如果数据过多,那么hashCode也可能重复,所以需要进行比较。时间主要花费在这上面。

那么结论显而易见,如果只是取值,直接用TryGetValue花费更小,更快速,更安全,找不到value时返回false;

在通过一个测试代码来验证时间的花费:

public class TestDictionary

{

static void Main(string[] args)

{

Dictionary test = new Dictionary { { "a", "b"} ,{ "a2","b2"} };

string x;

var start = DateTime.Now;

for (int i = 0; i != 10000000; i++)

{

test.TryGetValue("c", out x);

test.TryGetValue("b", out x);

}

Console.WriteLine(DateTime.Now - start);

//-------------------------------------

start = DateTime.Now;

for (int i = 0; i != 10000000; i++)

{

if (test.ContainsKey("c"))

{

x = test["a"];

}

if (test.ContainsKey("b"))

{

x = test["a2"];

}

}

Console.WriteLine(DateTime.Now - start);

Console.ReadLine();;

}

}

查找不存在的值时花费时间几乎相同

查找的值存在时,可以看出时间接近2倍

另外在提一下关于Keys的,因为在字典中键值对是成对存储的,使用keys会单独拿出所有的key来组成一个关于Key的数组,会产生额外的CG,如果不是要单独对keys进行处理,推荐少用这个。

用Unity自带的Profile来进行测试

public class test : MonoBehaviour

{

Dictionary testd = new Dictionary { { "a", null }, { "a2", "b2" } };

bool t = false;

// Update is called once per frame

void Update()

{

//让其只执行一次

if (!t) {

Nokeys();

Keys();

t = true;

}

}

//直接对字典进行迭代

void Nokeys() {

foreach (var key in testd)

{

Dosomething(key.Key);

}

}

//对Keys进行迭代

void Keys()

{

foreach (var key in testd.Keys) {

Dosomething(key);

}

}

void Dosomething(string key) { }

}

调用Keys方法时

未调用Keys方法

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐