使用哈希码来检测 List的元素是否为字符串的示例已经改变了C#

发布于 2024-11-02 19:08:58 字数 4818 浏览 3 评论 0原文

我有一个列表,它根据某些 XML 元素的 Linq 查询每分钟更新一次。

xml 会不时发生变化。有人建议我可以使用哈希码来确定列表中的任何字符串是否已更改。

我见过一些仅针对字符串而不是列表计算 Md5 哈希码的示例...有人可以向我展示一种使用列表执行此操作的方法吗?

我尝试了一些简单的方法,例如 int test = list1.GetHashCode;但无论列表中有什么,代码都是相同的......

这是带有链接查询和所有内容的整个方法......注意最后的 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");


    }

I have a List that updates every minute based on a Linq query of some XML elements.

the xml changes, from time to time. It was suggested to me that I could use Hashcode to determine if any of the strings in the list have changed.

I have seen some examples of Md5 hashcode calculations for just a string, but not for a list...could someone show me a way of doing this with a list?

I tried something simple like int test = list1.GetHashCode; but the code is the same no matter what is in the list...

here is the entire method with the link query and all..note the SequenceEqual at the end:

        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");


    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

爱你是孤单的心事 2024-11-09 19:08:58

为什么不直接使用 ObservableCollection 并监视列表的更改?

如果你真的想对整个列表进行哈希处理,你可能会这样做:

List<String> words;
int hash = String.Join("", words.ToArray()).GetHashCode();

我认为 MD5 可能有点大材小用,你不需要加密安全的哈希函数来完成此任务。

参考: String.JoinString.GetHashCode

why not just use an ObservableCollection and monitor changes to the list?

If you really wanted to hash an entire list, you might do something like this:

List<String> words;
int hash = String.Join("", words.ToArray()).GetHashCode();

I think MD5 may be overkill, you don't need a cryptographically secure hashing function for this task.

Reference: String.Join and String.GetHashCode

黄昏下泛黄的笔记 2024-11-09 19:08:58

如果您不打算拥有数十万个元素,或者您不打算每秒请求此函数数千次,我认为您不需要为所有哈希代码讨论而烦恼。

这是一个小程序,它将向您展示使用正确的方法比较 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 秒。

I don’t think you need to bother yourself about all the hash code discussion if you are not going to have hundreds thousands of elements or if you are not going to request this function thousands times a second.

Here is a small program that will show you how much time it will take to compare 10000 element using your correct way of doing this.

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();
    }
}

At my PC it took 0.001 seconds.

一直在等你来 2024-11-09 19:08:58

这是 Jon Skeet 的 GetHashCode() 实现,仅供参考。请注意,您必须弄清楚如何将其转化为比较列表/列表项所需的内容。

对于被覆盖的系统来说,最好的算法是什么。 Object.GetHashCode?

我在最近的一个项目中使用了它,效果很好。你不一定需要使用加密哈希来获得好的哈希码,你可以自己计算,但不应该天真地这样做。

Here is Jon Skeet's GetHashCode() implementation just for reference. Note that you'll have to figure out how to work this into what you need for comparing the list/list items.

What is the best algorithm for an overridden System.Object.GetHashCode?

I used this in a recent project and it worked great. You don't necessarily need to use a cryptographic hash to get a good hash code, you can calculate it yourself, but it should not be done naively.

帅的被狗咬 2024-11-09 19:08:58

您需要执行以下操作:

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
}

请注意,这可能会出现漏报(列表已更改,但哈希码不会检测到它)。 任何通过哈希码检测列表更改的方法均受此约束。

最后,根据您正在执行的操作(如果有多个线程访问列表),您可能需要考虑在计算哈希码和更新列表时锁定对列表的访问。这是否合适取决于您正在做什么。

You need to do something like this:

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;
    }
}

Now you can say:

int previousCode = list.GetHashCodeByElements();

A few minutes later:

int currentCode = list.GetHashCodeByElements();

if(previousCode != currentCode) {
    // list changed
}

Note that this is subject to false negatives (the list changed, but the hash code won't detect it). Any method of detecting changes in a list via hash codes is subject to this.

Finally, depending on what you are doing (if there are multiple threads hitting the list), you might want to consider locking access to the list while computing the hash code and updating the list. It depends on what you're doing whether or not this is appropriate.

没企图 2024-11-09 19:08:58

如果使用 HashSet 而不是 List,将会获得更好的性能。 HashSet 使用其元素的哈希码来比较它们。这可能就是你被告知的。

下一个示例演示如何使用 HashSet 更新列表并在每次 XML 更改时检测其中的更改。

HashSet 实现了与 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;
    }
}

You will have a better performance if you will use HashSet instead of List. HashSet uses hash codes of its element to compare them. That’s probably what you were told about.

The next example demonstrates how to update you list and detect changes in it every time your XML is changed using HashSet.

HashSet implement all the same interfaces as List. Thus, you can easily use it everywhere where you used your 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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文