我需要你的建议如下。
我有一个多维IList包含具有索引,Id和Text的项目。通常我知道Id的值,并根据我需要获取文本。 Id和Text值都是从数据库中读取的。
我们目前用于获取文本字段值的是:
foreach (Object myObj in List)
{
if (((MessageType)myObj).Id == id)
{
return ((MessageType)myObj).Text;
}
}
当IList中的计数变大(超过32K)时,处理需要一些时间。
问题:有没有办法在不迭代IList的情况下有效获取Text值?
我尝试的事情没有成功:
我无法使用AJAX / JQuery解决方案,因为它是一个现有的(实时)项目,重新编码将花费太多。
由于
答案 0 :(得分:4)
如果您希望通过32k元素的集合中的某个标识符进行快速搜索,则应使用Dictionary<K,V>
作为集合。
var dict = new Dictionary<IDType, MessageType>();
字典基本上是一个搜索树,其中元素以排序的方式存储,因此可以在不查看所有元素的情况下找到具有特定键(在您的情况下为Id)的元素。有关更多信息,请参阅MSDN。
如果您无法将集合重构为字典,则可以先填充字典(慢速),然后在字典中搜索(快速)。如果您在再次填写字典之前进行多次搜索,即如果您的列表不经常更改,则此速度会更快。
foreach(object o in List)
{
var msg = (MessageType)o;
dict.Add(msg.Id, msg);
}
搜索很容易:
MessageType msg = dict[id];
编辑:好吧,我好奇并编写了一个比较线性搜索和字典方法的测试程序。这是我使用的:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace ConsoleApplication1
{
class MessageType
{
public string Id;
public string Text;
}
class Program
{
static void Main(string[] args)
{
var rand = new Random ();
// filling a list with random text messages
List<MessageType> list = new List<MessageType>();
for (int i = 0; i < 32000; i++)
{
string txt = rand.NextDouble().ToString();
var msg = new MessageType() {Id = i.ToString(), Text = txt };
list.Add(msg);
}
IList List = (IList)list;
// doing some random searches
foreach (int some in new int[] { 2, 10, 100, 1000 })
{
var watch1 = new Stopwatch();
var watch2 = new Stopwatch();
Dictionary<string, MessageType> dict = null;
for (int i = 0; i < some; i++)
{
string id = rand.Next(32000).ToString();
watch1.Start();
LinearLookup(List, id);
watch1.Stop();
watch2.Start();
// fill once
if (dict == null)
{
dict = new Dictionary<string, MessageType>();
foreach (object o in List)
{
var msg = (MessageType)o;
dict.Add(msg.Id, msg);
}
}
// lookup
DictionaryLookup(dict, id);
watch2.Stop();
}
Console.WriteLine(some + " x LinearLookup took "
+ watch1.Elapsed.TotalSeconds + "s");
Console.WriteLine("Dictionary fill and " + some
+ " x DictionaryLookup took "
+ watch2.Elapsed.TotalSeconds + "s");
}
}
static string LinearLookup(IList List, string id)
{
foreach (object myObj in List)
{
if (((MessageType)myObj).Id == id)
{
return ((MessageType)myObj).Text;
}
}
throw new Exception();
}
static string DictionaryLookup(Dictionary<string, MessageType> dict,
string id)
{
return dict[id].Text;
}
}
}
我在Release / x86中得到的结果:
Number of | Time [ms] with | Time[ms] with | Speedup (approx.)
searches | linear search | dictionary(*) | with dictionary
----------+----------------+---------------+-----------------
2 | 1.161 | 2.006 | 0.6
----------+----------------+---------------+-----------------
10 | 2.834 | 2.060 | 1.4
----------+----------------+---------------+-----------------
100 | 25.39 | 1.973 | 13
----------+----------------+---------------+-----------------
1000 | 261.4 | 5.836 | 45
----------+----------------+---------------+-----------------
(*) including filling the dictionary once.
所以,我有点乐观地说,搜索两次已经得到了回报。在我的测试应用程序中,我必须搜索10次以使字典更快。
对不起,我无法做出更实际的例子,我的Ids全部排序。尽管可以尝试修改和试验; - )
答案 1 :(得分:1)
从它的外观来看,这里有List<MessageType>
,这不是多维的。而是列表中的 对象具有多个属性。
使用LINQ可以轻松地将它们排除在最有可能的循环之外:
var text = (from MessageType msgType in myList
where msgType.Id == id
select msgType.Text).FirstOrDefault();
使用内联LINQ语句甚至更容易:
var text = myList.Where(s => s.Id == id).Select(s => s.Text).FirstOrDefault();
注意:如上面的注释中所述,这些LINQ语句的速度仅与对象在List中的位置一样好。如果它是列表中的最后一个对象,您可能会看到相同的性能差异。 Dictionary<Index, MessageType>
将会更高效。
答案 2 :(得分:0)
更好的方法是使用ILookup。 例如:
if (look.Contains(myID)){
var name = look[myID].First();
}
并使用:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class stackedExample(QWidget):
def __init__(self):
super(stackedExample, self).__init__()
self.rightlist = QListWidget()
self.rightlist.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
self.rightlist.insertItem(0, 'Contact')
self.stack1 = QWidget()
self.stack1.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Minimum)
self.stack1UI()
self.Stack = QStackedWidget(self)
self.Stack.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Minimum)
self.Stack.addWidget(self.stack1)
hbox = QHBoxLayout(self)
hbox.addWidget(self.Stack)
hbox.addWidget(self.rightlist)
self.setLayout(hbox)
self.rightlist.currentRowChanged.connect(self.display)
self.setGeometry(300, 50, 10, 10)
self.setWindowTitle('StackedWidget demo')
self.show()
def stack1UI(self):
layout = QVBoxLayout()
label = QLabel("Hello World")
label.setSizePolicy(QSizePolicy.Minimum,QSizePolicy.Minimum)
label.setStyleSheet("QLabel { background-color : red; color : blue; }")
layout.addWidget(label)
self.stack1.setLayout(layout)
def display(self, i):
self.Stack.setCurrentIndex(i)
def main():
app = QApplication(sys.argv)
ex = stackedExample()
sys.exit(app.exec_())
if __name__ == '__main__':
main()