Đừng bao giờ quên nguyên tắc này: Làm cho nó chính xác, làm cho nó rõ ràng, làm cho nó ngắn gọn, làm cho nó nhanh. Theo thứ tự đó. Vì vậy, mã đầu tiên lên thi ngây thơ:
static IEnumerable<T> GetByIndex<T>(
List<T> list,
Func<T, TIndex> func,
TIndex key
) {
return list.Where(x => func(x) == key);
}
Cách sử dụng:
List<Test> tests = new List<Test>() {
new Test { Name = "aaa", Value = 111, Valid = Valid.Yes },
new Test { Name = "aaa", Value = 111, Valid = Valid.Yes },
new Test { Name = "bbb", Value = 112, Valid = Valid.No },
new Test { Name = "bbb", Value = 111, Valid = Valid.No },
new Test { Name = "bbb", Value = 220, Valid = Valid.No },
new Test { Name = "ccc", Value = 220, Valid = Valid.Yes }
};
IEnumerable<Test> lookup = GetByIndex(tests, x => x.Name, "bbb");
Trên đây là chính xác, rõ ràng và súc tích. Hầu như chắc chắn nó đủ nhanh cho mục đích của bạn.
Vì vậy, càng xa càng làm cho nó nhanh bạn phải biện pháp đầu tiên:
- Xây dựng tiêu chí hiệu suất hợp lý.
- Thiết lập giường thử nghiệm của dữ liệu trong thế giới thực.
- Lập hồ sơ cách tiếp cận đơn giản chống lại giường thử nghiệm của dữ liệu trong thế giới thực. Lưu ý ở đây rằng lược tả bao gồm suy luận xem chức năng này có phải là nút cổ chai trong ứng dụng của bạn hay không.
Sau đó, nếu và chỉ nếu điều này không đủ nhanh cho bạn, bạn nên cố gắng tối ưu hóa. Nó sẽ không quá khó để thực hiện một IndexedList<T> : ICollection<T>
mà sẽ cho phép bạn lập chỉ mục ra khỏi các thuộc tính khác nhau.
Đây là một thực hiện ngây thơ mà có thể giúp bạn bắt đầu:
class IndexedList<T> : IEnumerable<T> {
List<T> _list;
Dictionary<string, Dictionary<object, List<T>>> _dictionary;
Dictionary<string, Func<T, object>> _propertyDictionary;
public IndexedList(IEnumerable<string> propertyNames) : this(propertyNames, new List<T>()) { }
public IndexedList(IEnumerable<string> propertyNames, IEnumerable<T> source) {
_list = new List<T>();
_dictionary = new Dictionary<string, Dictionary<object, List<T>>>();
_propertyDictionary = BuildPropertyDictionary(propertyNames);
foreach (var item in source) {
Add(item);
}
}
static Dictionary<string, Func<T, object>> BuildPropertyDictionary(IEnumerable<string> keys) {
var propertyDictionary = new Dictionary<string,Func<T,object>>();
foreach (string key in keys) {
ParameterExpression parameter = Expression.Parameter(typeof(T), "parameter");
Expression property = Expression.Property(parameter, key);
Expression converted = Expression.Convert(property, typeof(object));
Func<T, object> func = Expression.Lambda<Func<T, object>>(converted, parameter).Compile();
propertyDictionary.Add(key, func);
}
return propertyDictionary;
}
public void Add(T item) {
_list.Add(item);
foreach (var kvp in _propertyDictionary) {
object key = kvp.Value(item);
Dictionary<object, List<T>> propertyIndex;
if (!_dictionary.TryGetValue(kvp.Key, out propertyIndex)) {
propertyIndex = new Dictionary<object, List<T>>();
_dictionary.Add(kvp.Key, propertyIndex);
}
List<T> list;
if (!propertyIndex.TryGetValue(key, out list)) {
list = new List<T>();
propertyIndex.Add(key, list);
}
propertyIndex[key].Add(item);
}
}
public IEnumerable<T> GetByIndex<TIndex>(string propertyName, TIndex index) {
return _dictionary[propertyName][index];
}
public IEnumerator<T> GetEnumerator() {
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
Cách sử dụng:
List<Test> tests = new List<Test>() {
new Test { Name = "aaa", Value = 111, Valid = Valid.Yes },
new Test { Name = "aaa", Value = 111, Valid = Valid.Yes },
new Test { Name = "bbb", Value = 112, Valid = Valid.No },
new Test { Name = "bbb", Value = 111, Valid = Valid.No },
new Test { Name = "bbb", Value = 220, Valid = Valid.No },
new Test { Name = "ccc", Value = 220, Valid = Valid.Yes }
};
// build an IndexedList<Text> indexed by Name and Value
IndexedList<Test> indexed = new IndexedList<Test>(new List<string>() { "Name", "Value" }, tests);
// lookup where Name == "bbb"
foreach (var result in indexed.GetByIndex("Name", "bbb")) {
Console.WriteLine(result.Value);
}
Nhưng thấy, lý do bạn không làm điều này trừ khi việc thực hiện ngây thơ chưa được nhanh đủ là vì sự phức tạp bổ sung mà bạn vừa thêm vào hệ thống của mình. Bạn vừa thêm mã mới để duy trì, mã mới để kiểm tra và có thể không đạt được bất kỳ thứ gì nếu dữ liệu trong thế giới thực của bạn không nhanh hơn hoặc không phải là một nút cổ chai của ứng dụng của bạn.
Âm thanh đầy hứa hẹn; Tôi sẽ xem nó ... – pbz
Ý tưởng đằng sau i4o rất gọn gàng và tôi nghĩ nó nên được xây dựng trong khung công tác. Thật không may, vì nó là ngay bây giờ nó được giới hạn trong một đơn giản, nơi điều kiện (tức là chỉ nơi một cái gì đó = "giá trị", không && hoặc ||). Đối với trường hợp của tôi nó là đủ mặc dù. Cảm ơn. – pbz