我有一个List,它根据某些XML元素的Linq查询每分钟更新一次。
xml会不时发生变化。有人向我建议我可以使用Hashcode来确定列表中的任何字符串是否已更改。
我已经看到了一些Md5哈希码计算的例子只是一个字符串,但不是列表...有人能告诉我一个用列表做这个的方法吗?
我试过像int test = list1.GetHashCode这样简单的东西;但无论列表中的内容如何,代码都是相同的......
这是带有链接查询的整个方法,最后是所有..note的SequenceEqual:
private void GetTrackInfo()
{
_currentTitles1.Clear();
var savedxmltracks = new XDocument();
listBox1.Items.Clear();
WebClient webClient = new WebClient();
XmlDocument xmltracks = new XmlDataDocument();
try
{
xmltracks.Load(_NPUrl);
xmltracks.Save("xmltracks.xml");
}
catch (WebException ex)
{
StatusLabel1.Text = ex.Message;
}
try
{
savedxmltracks = XDocument.Load("xmltracks.xml");
}
catch (Exception ex)
{
StatusLabel1.Text = ex.Message;
}
var dateQuery = from c in savedxmltracks.Descendants("content")
select c;
_count = savedxmltracks.Element("content").Element("collection").Attribute("count").Value;
var tracksQuery1 = from c in savedxmltracks.Descendants("data")
select new
{
title = c.Attribute("title").Value,
imageurl = c.Attribute("image").Value,
price = c.Attribute("price").Value,
description = c.Attribute("productdescription").Value,
qualifier = c.Attribute("pricequalifier").Value
};
var xml = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
new XElement("LastUsedSettings",
new XElement("TimerInterval",
new XElement("Interval", Convert.ToString(numericUpDown1.Value))),
new XElement("NowPlayingURL",
new XElement("URL", _NPUrl)),
new XElement("Email", emailAddress),
new XElement("LastUpdated", DateTime.Now.ToString())));
XElement StoreItems = new XElement("StoreItems");
int i = 0;
foreach (var c in tracksQuery1)
{
if (c.title.Length <= 40 & c.qualifier.Length <= 12 & i < 10)
{
if (c.title != null) _title1 = c.title;
if (c.imageurl != null) _imageUrl = c.imageurl;
if (c.price != null) _price = c.price;
if (c.description != null) _productDescription = c.description;
if (c.qualifier != null) _priceQualifier = c.qualifier;
//}
StoreItems.Add(new XElement("Title" + i.ToString(), _title1));
_currentTitles1.Add(_title1);
if (_oldTitles1.Count > 0)
{
Console.WriteLine("OldTitle: {0}, NewTitle: {1}", _oldTitles1[i], _currentTitles1[i]);
}
StoreItems.Add(new XElement("Price" + i.ToString(), _price));
StoreItems.Add(new XElement("Description" + i.ToString(), _productDescription));
StoreItems.Add(new XElement("PriceQualifier" + i.ToString(), _priceQualifier));
listBox1.Items.Add("Title: " + _title1);
listBox1.Items.Add("Image URL: " + _imageUrl);
listBox1.Items.Add("Price: " + _price);
listBox1.Items.Add("Description: " + _productDescription);
listBox1.Items.Add("PriceQualifier: " + _priceQualifier);
try
{
imageData = webClient.DownloadData(_imageUrl);
}
catch (WebException ex)
{
StatusLabel1.Text = ex.Message;
}
MemoryStream stream = new MemoryStream(imageData);
Image img = Image.FromStream(stream);
//Image saveimage = img;
//saveimage.Save("pic.jpg");
img.Save("pic" + i.ToString() + ".jpg");
stream.Close();
i++;
}
}
//Console.WriteLine("Count: " + _count);
Console.WriteLine("oldTitles Count: " + _oldTitles1.Count.ToString());
Console.WriteLine("currentTitles Count: " + _currentTitles1.Count.ToString());
if (_oldTitles1.Count == 0) _oldTitles1 = _currentTitles1;
if (!_oldTitles1.SequenceEqual(_currentTitles1))
{
Console.WriteLine("Items Changed!");
SendMail();
_oldTitles1 = _currentTitles1;
}
xml.Root.Add(StoreItems);
xml.Save("settings.xml");
}
答案 0 :(得分:5)
为什么不使用ObservableCollection并监控对列表的更改?
如果你真的想要散列整个列表,你可能会这样做:
List<String> words;
int hash = String.Join("", words.ToArray()).GetHashCode();
我认为MD5可能过度,你不需要加密安全散列函数来完成这项任务。
答案 1 :(得分:0)
这是Jon Skeet的GetHashCode()
实现仅供参考。请注意,您必须弄清楚如何将其用于比较列表/列表项所需的内容。
What is the best algorithm for an overridden System.Object.GetHashCode?
我在最近的一个项目中使用了它,效果很好。您不一定需要使用加密哈希来获得良好的哈希代码,您可以自己计算,但不应该天真地进行。
答案 2 :(得分:0)
你需要做这样的事情:
public static class ListExtensions {
private readonly static int seed = 17;
private readonly static int multiplier = 23;
public static int GetHashCodeByElements<T>(this List<T> list) {
int hashCode = seed;
for(int index = 0; index < list.Count; list++) {
hashCode = hashCode * multiplier + list[index].GetHashCode();
}
return hashCode;
}
}
现在你可以说:
int previousCode = list.GetHashCodeByElements();
几分钟后:
int currentCode = list.GetHashCodeByElements();
if(previousCode != currentCode) {
// list changed
}
请注意,这可能会出现漏报(列表已更改,但哈希码不会检测到它)。 通过哈希码检测列表中的更改的任何方法都受此限制。
最后,根据您正在做的事情(如果有多个线程点击列表),您可能需要在计算哈希码和更新列表时考虑lock
对列表的访问。这取决于你正在做什么,不管这是否合适。
答案 3 :(得分:0)
如果您使用HashSet而不是List,您将获得更好的性能。 HashSet使用其元素的哈希码来比较它们。这可能就是你被告知的事情。
下一个示例演示了每次使用HashSet更改XML时如何更新列表并检测其中的更改。
HashSet实现与List相同的所有接口。因此,您可以在使用List的任何地方轻松使用它。
public class UpdatableList
{
public HashSet<string> TheList { get; private set; }
//Returns true if new list contains different elements
//and updates the collection.
//Otherwise returns false.
public bool Update(List<String> newList)
{
if (TheList == null)
{
TheList = new HashSet<string>(newList);
return true;
}
foreach (var item in newList)
{
//This operation compares elements hash codes but not
//values itself.
if (!TheList.Contains(item))
{
TheList = new HashSet<string>(newList);
return true;
}
}
//It gets here only if both collections contain identical strings.
return false;
}
}
答案 4 :(得分:0)
如果您不会拥有数十万个元素,或者如果您不打算每秒数千次请求此函数,我认为您不需要为所有哈希代码讨论烦恼。
这是一个小程序,它将向您显示使用正确的方法比较10000元素需要多长时间。
class Program
{
static void Main(string[] args)
{
var list1 = new List<string>();
var list2 = new List<string>();
for (int i = 0; i < 10000; i++)
{
list1.Add("Some very very very very very very very long email" + i);
list2.Add("Some very very very very very very very long email" + i);
}
var timer = new Stopwatch();
timer.Start();
list1.SequenceEqual(list2);
timer.Stop();
Console.WriteLine(timer.Elapsed);
Console.ReadKey();
}
}
在我的电脑上花了0.001秒。