2010-04-12 31 views
31

tôi bị bệnh làm các khối mã như thế này cho bit khác nhau của mã tôi có:điển .net và tra cứu thêm/cập nhật

if (dict.ContainsKey[key]) { 
    dict[key] = value; 
} 
else { 
    dict.Add(key,value); 
} 

và tra cứu (tức là chìa khóa -> danh sách các giá trị)

if (lookup.ContainsKey[key]) { 
    lookup[key].Add(value); 
} 
else { 
    lookup.Add(new List<valuetype>); 
    lookup[key].Add(value); 
} 

Có một bộ sưu tập lib hoặc phương pháp mở rộng khác mà tôi nên sử dụng để thực hiện điều này trong một dòng mã không có vấn đề gì về khóa và giá trị?

ví dụ:

dict.AddOrUpdate(key,value) 
lookup.AddOrUpdate(key,value) 
+0

'tra cứu 'một' ILookup '? Tôi nghĩ không phải vì nó không có phương thức 'ContainsKey'. Chỉ cần xác nhận .NET đã không thay đổi tra cứu vì câu hỏi được hỏi, vì đang tìm cách cập nhật 'ILookup' ... – drzaus

Trả lời

32

Như Evgeny nói, indexer sẽ đã thay thế giá trị hiện có - vì vậy nếu bạn chỉ muốn vô điều kiện thiết lập giá trị cho một phím nào đó, bạn có thể làm

dictionary[key] = value; 

Trường hợp thú vị hơn là "có được một giá trị, hoặc chèn nó nếu cần thiết". Dễ dàng thực hiện với phương pháp tiện ích mở rộng:

public static TValue GetOrCreateValue<TKey, TValue> 
    (this IDictionary<TKey, TValue> dictionary, 
    TKey key, 
    TValue value) 
{ 
    return dictionary.GetOrCreateValue(key,() => value); 
} 

public static TValue GetOrCreateValue<TKey, TValue> 
    (this IDictionary<TKey, TValue> dictionary, 
    TKey key, 
    Func<TValue> valueProvider) 
{ 
    TValue ret; 
    if (!dictionary.TryGetValue(key, out ret)) 
    { 
     ret = valueProvider(); 
     dictionary[key] = ret; 
    } 
    return ret; 
} 

Lưu ý việc sử dụng đại biểu để tạo giá trị mặc định - tạo điều kiện thuận lợi cho các trường hợp như "danh sách giá trị"; bạn không muốn tạo danh sách trống trừ khi bạn phải:

dict.GetOrCreateValue(key,() => new List<int>()).Add(item); 

Cũng lưu ý cách này chỉ thực hiện việc tra cứu một lúc nếu phím đã có mặt - không cần phải làm một cái nhìn ContainsKeysau đó tăng giá trị. Nó vẫn đòi hỏi hai tra cứu khi nó tạo ra giá trị mới mặc dù.

1

Im không chắc chắn nếu có một phương pháp như bạn yêu cầu, nhưng bạn có thể viết một hàm nhỏ cho nó, hoặc sử dụng các ngoại lệ cố gắng nắm bắt, có lẽ nếu bạn cố gắng thêm một giá trị đã tồn tại nó sẽ ném một ngoại lệ. Nếu bạn nắm bắt điều đó và bỏ qua nó ... Chỉ cần một gợi ý

4

ConcurrentDictionary in .NET 4.0 có this nice method. Bạn cũng có thể viết một phương pháp mở rộng cho việc này.

14

Khi cập nhật, bạn không cần thực hiện séc. Chỉ cần sử dụng:

dict[key] = value 

Nó sẽ thay thế bất kỳ giá trị hiện có nào. Khi lấy giá trị không may, không có phương thức đơn nào thuận tiện (như setdefault bằng Python), nhưng bạn có thể tạo phương thức mở rộng của riêng mình. Một cái gì đó như thế này:

if (!lookup.TryGetValue(key, out value)) 
{ 
    value = new List<T>(); 
    lookup.Add(key, value); 
} 
3

Nếu làm việc với .NET Framework 4 hoặc mới hơn, bạn có thể sử dụng AddOrUpdate Method

dict.AddOrUpdate(key,value) 

add hoặc cập nhật là như thế này

dict[key] = value; 
+4

Điều này chỉ có sẵn cho 'ConcurrentDictionary' – Mrchief

+0

Có, bạn sử dụng nó với Từ điển đồng thời vì bạn không' t muốn rơi vào một cái bẫy nơi bạn kiểm tra điều kiện thêm, xác định rằng bạn cần phải làm thêm, sau đó có cái gì khác làm thêm phía sau lưng của bạn. AddOrUpdate làm cho nó nguyên tử, tôi tin. – quillbreaker

0

Tôi thích AddOrUpdate phương pháp ConcurrentDictionary, nhưng tôi thích hiệu suất của bộ sưu tập từ điển quá :) Vì vậy, đây là phương pháp mở rộng cho tất cả các lớp thực hiện IDictionary.

public static TValue AddOrUpdate<TKey, TValue>(
    this IDictionary<TKey, TValue> dict, 
    TKey key, 
    TValue addValue, 
    Func<TKey, TValue, TValue> updateValueFactory) 
{ 
    TValue existing; 
    if (dict.TryGetValue(key, out existing)) 
    { 
     addValue = updateValueFactory(key, existing); 
     dict[key] = addValue; 
    } 
    else 
    { 
     dict.Add(key, addValue); 
    } 

    return addValue; 
} 


public static TValue AddOrUpdate<TKey, TValue>(
    this IDictionary<TKey, TValue> dict, 
    TKey key, 
    Func<TKey, TValue> addValueFactory, 
    Func<TKey, TValue, TValue> updateValueFactory) 
{ 
    TValue existing; 
    if (dict.TryGetValue(key, out existing)) 
    { 
     existing = updateValueFactory(key, existing); 
     dict[key] = existing; 
    } 
    else 
    { 
     existing = addValueFactory(key); 
     dict.Add(key, existing); 
    } 

    return existing; 
} 
Các vấn đề liên quan