pbz*_*pbz 13 .net c# indexing collections list
给定一个通用List我需要某种索引(在数据库意义上),这将允许我快速检索.这个索引的键不是唯一的,所以我不能使用字典.这就是我的想法:给定一个类Foo {P1,P2,P3}可能有这样的数据
{ "aaa", 111, "yes" }
{ "aaa", 112, "no" }
{ "bbb", 111, "no" }
{ "bbb", 220, "yes" }
{ "bbb", 220, "no" }
{ "ccc", 300, "yes" }
Run Code Online (Sandbox Code Playgroud)
我需要快速访问P1为"bbb"(第3,第4和第5)的所有记录或P2为111(第1和第3)的所有记录.我可以使用排序列表,但如果我需要多种排序/索引方法,我最终会得到重复列表.
.NET框架中是否有内置的东西,或者可能是OS库,它会做这样的事情?谢谢.
PS我提到"排序列表"的想法是排序列表将更快地返回/找到项目.我不需要列表必须排序; 我只是在寻找快速检索/发现.
jas*_*son 13
永远不要忘记这个原则:做到正确,说清楚,简洁,快速.以该顺序.所以,首先编写天真的实现代码:
static IEnumerable<T> GetByIndex<T>(
List<T> list,
Func<T, TIndex> func,
TIndex key
) {
return list.Where(x => func(x) == key);
}
Run Code Online (Sandbox Code Playgroud)
用法:
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");
Run Code Online (Sandbox Code Playgroud)
以上是正确,清晰和简洁的.几乎可以肯定它足够快,适合您的目的.
因此,只要加快速度,您必须先测量:
然后,如果且仅当这不够快你应该尝试优化.实现一个IndexedList<T> : ICollection<T>允许你索引各种属性的东西并不会太难.
这是一个天真的实现,可以帮助您入门:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
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);
}
Run Code Online (Sandbox Code Playgroud)
但是请注意,除非天真的实现还不够快,否则你不这样做的原因是因为你刚刚添加到系统中的额外复杂性.您刚刚添加了新代码来维护,需要测试新代码,如果现实数据速度不快或者不是应用程序的瓶颈,则可能无法获得任何代码.
Pat*_*her 12
(编辑精心制作基于收集的策略)
.NET中没有内部结构可供查找使用各种索引.这是两个好的策略:
选项1:LINQ,灵活性和简单性
为了简化和许多其他集成选项,创建一个List(或其他实现IEnumerable的)自定义类型,并使用LINQ进行按需查找.请注意,如果方便,您可以使用匿名类型.您还可以将数据保存在XML结构中,并且仍然可以完成所有这些操作.您可能能够获取数据,执行查找以及在少量明确代码中操作结果.在.Net 4.0中,您可以使用并行 Ling(PLINQ)轻松地利用多核处理这一过程.
List<foo> bigFooList = new List<foo>
{
new Foo {"aaa", 111, "yes"},
new Foo {"aaa", 112, "no"},
new Foo {"bbb", 111, "no"},
new Foo {"bbb", 220, "yes"},
new Foo {"bbb", 220, "no"},
new Foo {"ccc", 300, "yes"}
};
var smallFooList = From f In bigFooList Where f.P2 = 220 Select f;
Run Code Online (Sandbox Code Playgroud)
选项2:多个集合,用于索引查找功能.
如果您在大型集上执行大量查找并需要电源,则可以使用多个集合来实现更快的查找.棘手的部分是您要求可以复制索引值.以下是一些策略:
Lookup<string, foo> LookupP1 = (Lookup<string, foo>) fooList.ToLookup(f => f.P1, f => p)Dictionary<T, List<foo>>为每个需要按索引搜索的字段创建一个,其中T是该值的类型.因此,对于您的示例,我们将创建:var FoosByP1 = new Dictionary<String,List<foo>>var FoosByP2 = new Dictionary<Int32,List<foo>>等等.Dictionary<T, List<Int32>>,其中整数将是Foo的索引中央词典中的项目.这样可以节省内存并且仍然非常快.| 归档时间: |
|
| 查看次数: |
11965 次 |
| 最近记录: |