【问题标题】:C# Storing multiple Items in multiple arrays for comparisonC#将多个项目存储在多个数组中以进行比较
【发布时间】:2011-07-22 08:43:42
【问题描述】:

我有一个从 XML 读取文件名及其等效哈希码的应用程序(在我使用相同的应用程序创建 XML 之后),我想做的是比较一个 XML(文件及其哈希码) 到另一个 XML(可能有不同的文件和哈希码)。我正在尝试创建一个比较函数,以便我可以首先比较两个 XML 之间的文件名,然后如果两个 XML 中都存在文件,则比较哈希码。

(为了帮助理解我试图实现的基本目标,我有 2 个彼此相邻的列表框,每个 xml 都有一个。一旦我比较它们,我希望两个列表框都填充所有文件名,但不填充哈希码,然后用不同的颜色标记它们,具体取决于它们是相同的文件、相同的文件但内容不同或文件在其他 XML 中根本不存在。)

我正在努力寻找一种方法来存储文件名及其哈希码。

代码(我正在使用我创建的 C++ Dll 来完成一些工作):

 private String[] ProjOne()
        {
            //Intialize the functions in the DLL
            DllTest.Funtions Functions = new DllTest.Funtions();

            //Set the location where the XMLs can be found
            String Directory = "C:\\Users\\brandonm\\Desktop\\Backup\\XML\\";

            //Get and set the number of items in the directory
            int NumFiles = Functions.GetNumFiles(Directory);

            //Create a search string to be used to determine the fullpath name of the file
            //selected from the combobox
            String SelectedFile = comboBox1.SelectedItem.ToString();
            String SearchString = "*" + SelectedFile + "*.XML";

            //Get and set the TC that will be used to get the filenames and hashcodes
            int SelectedTC = int.Parse(comboBox2.SelectedItem.ToString());

            //Get and set an array containing a full path structure to the item selected from
            //the combobox using the search string created earlier. Get files returns an array
            //thus needs to be stored in an array
            String[] FullPaths = new String[NumFiles];
            FullPaths = System.IO.Directory.GetFiles("C:\\Users\\brandonm\\Desktop\\Backup\\XML", SearchString, System.IO.SearchOption.AllDirectories);
            int number = FullPaths.GetLength(0);

            // The number of items in the XML ie. Number of Filenames in a particular TC
            int NumXMLItems = NumXMLItemsListOne();

            // Initialize the array that will hold the Filenames and their equivalent Hashcodes
            String[] FileNames = new String[NumXMLItems];
            String[] HashCode = new String[NumXMLItems];
            String[,] ProjectOne = new String[HashCode.Length, HashCode.Length];

            //Itteration through the all the XMLs in the location to add the current items into their arrays
            for (int x = 0; x < NumFiles; x++)
            {
                String FullPath = FullPaths[x];

                XPathNavigator Root = new XPathDocument(FullPath).CreateNavigator();

                foreach (XPathNavigator Cycle in Root.Select(String.Format(@"//TestCycle[@Number = '{0}']", SelectedTC)))
                {
                    foreach (XPathNavigator Nav in Cycle.Select(@"Files/FileName/@File"))
                    {
                        int y = 0;
                        FileNames[y] = Nav.Value;
                        y = y + 1;
                    }
                    foreach (XPathNavigator Nav in Cycle.Select(@"Files/HashCode/@Code"))
                    {
                        int z = 0;
                        HashCode[z] = Nav.Value;
                        z = z + 1;
                    }
                }
            }
            return FileNames;
        }

XML:

<?xml version="1.0" encoding="utf-8"?>
<Projects>
  <Project Name="tfasdtyf">
    <TestCycle Number="2387468">
      <Files>
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\DllTest.dll" />
        <HashCode Code="0E-C5-03-AD-CC-21-62-49-D9-36-3F-C4-F1-17-BC-11" />
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\WpfDllTest.exe" />
        <HashCode Code="60-46-A3-6F-82-E4-0A-00-2A-60-83-47-B2-16-F3-24" />
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\WpfDllTest.vshost.exe" />
        <HashCode Code="76-7B-6F-37-0D-3A-F2-F4-32-D1-70-A5-75-3B-DE-95" />
      </Files>
    </TestCycle>
  </Project>
  <Project Name="tfasdtyf">
    <TestCycle Number="23423">
      <Files>
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\DllTest.dll" />
        <HashCode Code="0E-C5-03-AD-CC-21-62-49-D9-36-3F-C4-F1-17-BC-11" />
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\WpfDllTest.exe" />
        <HashCode Code="60-46-A3-6F-82-E4-0A-00-2A-60-83-47-B2-16-F3-24" />
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\WpfDllTest.vshost.exe" />
        <HashCode Code="76-7B-6F-37-0D-3A-F2-F4-32-D1-70-A5-75-3B-DE-95" />
      </Files>
    </TestCycle>
  </Project>
  <Project Name="tfasdtyf">
    <TestCycle Number="1112">
      <Files>
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\DllTest.dll" />
        <HashCode Code="0E-C5-03-AD-CC-21-62-49-D9-36-3F-C4-F1-17-BC-11" />
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\WpfDllTest.exe" />
        <HashCode Code="60-46-A3-6F-82-E4-0A-00-2A-60-83-47-B2-16-F3-24" />
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\WpfDllTest.vshost.exe" />
        <HashCode Code="76-7B-6F-37-0D-3A-F2-F4-32-D1-70-A5-75-3B-DE-95" />
      </Files>
    </TestCycle>
  </Project>
  <Project Name="tfasdtyf">
    <TestCycle Number="999">
      <Files>
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\DllTest.dll" />
        <HashCode Code="0E-C5-03-AD-CC-21-62-49-D9-36-3F-C4-F1-17-BC-11" />
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\WpfDllTest.exe" />
        <HashCode Code="60-46-A3-6F-82-E4-0A-00-2A-60-83-47-B2-16-F3-24" />
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\WpfDllTest.vshost.exe" />
        <HashCode Code="76-7B-6F-37-0D-3A-F2-F4-32-D1-70-A5-75-3B-DE-95" />
      </Files>
    </TestCycle>
  </Project>
  <Project Name="tfasdtyf">
    <TestCycle Number="34534">
      <Files>
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\DllTest.dll" />
        <HashCode Code="0E-C5-03-AD-CC-21-62-49-D9-36-3F-C4-F1-17-BC-11" />
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\WpfDllTest.exe" />
        <HashCode Code="60-46-A3-6F-82-E4-0A-00-2A-60-83-47-B2-16-F3-24" />
        <FileName File="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\WpfDllTest.vshost.exe" />
        <HashCode Code="76-7B-6F-37-0D-3A-F2-F4-32-D1-70-A5-75-3B-DE-95" />
      </Files>
    </TestCycle>
  </Project>
  <Project Name="Music">
    <TestCycle Number="12312">
      <Files>
        <FileName File="C:\Users\brandonm\Desktop\Stuff\Dubstep\01 A1 Shut Ya Mouth.mp3" />
        <HashCode Code="3E-92-80-93-D5-64-19-16-26-8D-39-2A-C7-0B-C8-EB" />
        <FileName File="C:\Users\brandonm\Desktop\Stuff\Dubstep\01 A1 Snake Eater.mp3" />
        <HashCode Code="8B-DF-19-AE-87-52-64-2E-85-CF-57-4B-85-4D-CC-E9" />
        <FileName File="C:\Users\brandonm\Desktop\Stuff\Dubstep\01 A1 Stuck in the System.mp3" />
        <HashCode Code="6A-30-A7-53-FF-29-A5-DF-6D-24-DF-41-74-EE-06-4D" />
        <FileName File="C:\Users\brandonm\Desktop\Stuff\Dubstep\01 Martin Solveig - Hello (Featuring Dragonette).mp3" />
        <HashCode Code="93-90-A3-9C-BE-81-63-03-D7-96-1F-72-E4-ED-2D-32" />
        <FileName File="C:\Users\brandonm\Desktop\Stuff\Dubstep\01 Stimming - Funkworm.mp3" />
        <HashCode Code="8F-E1-7A-F1-B7-80-C6-2F-DC-34-FD-82-A0-DA-35-5E" />
        <FileName File="C:\Users\brandonm\Desktop\Stuff\Dubstep\1. Downlink - Ignition.mp3" />
        <HashCode Code="3D-89-B3-C2-73-A6-A0-85-02-C0-B4-F9-C8-09-14-C7" />
        <FileName File="C:\Users\brandonm\Desktop\Stuff\Dubstep\02 B1 Psychedelic Runway.mp3" />
        <HashCode Code="00-72-5C-CE-25-73-98-31-69-71-68-48-31-A1-A3-5A" />
        <FileName File="C:\Users\brandonm\Desktop\Stuff\Dubstep\02 B1 Rapture.mp3" />
        <HashCode Code="1E-A6-53-07-10-FD-A3-4C-EF-D6-92-7F-CE-97-88-6E" />
        <FileName File="C:\Users\brandonm\Desktop\Stuff\Dubstep\02_Digital-Controller.mp3" />
        <HashCode Code="94-E0-CA-5F-2B-D2-56-7B-AF-2E-04-50-58-38-4D-B4" />
        <FileName File="C:\Users\brandonm\Desktop\Stuff\Dubstep\2. Downlink - Gamma Ray.mp3" />
        <HashCode Code="3C-7A-76-AD-A6-2C-D1-7E-61-24-C0-40-BD-A7-A9-41" />
      </Files>
    </TestCycle>
  </Project>
</Projects>

我目前有另一个与上述相同的功能,因此每个列表框都有一个功能,唯一的区别是文件和 testcyle 编号,它决定了他们将在 XML 中检索文件和哈希码的位置。它们将它们存储在 4 个单独的数组中,每个函数 2 个数组。但显然我的函数不能返回两个数组,所以它目前只返回一个。

二维数组让我很困惑,我不确定当涉及到我需要做的比较时,我如何从它们那里获得我需要的信息。谁能指导我以更好的方式做到这一点?

我不想真正为每组文件名和每组哈希码创建 4 个像上面的函数。但我仍然是初学者,所以也许这是我最好的选择?

【问题讨论】:

    标签: c# arrays comparison


    【解决方案1】:

    最好不要复制函数。您想在此处创建一个可用于所有情况的函数。

    至于存储文件名和哈希码,.NET 有很多有用的集合类可供您使用。例如,您可以像这样使用Dictionary&lt;string, string&gt;

            Dictionary<string, string> dictionary = new Dictionary<string, string>();
    
            for (int i = 0; i < NumFiles; i++)
            {
                dictionary.Add(FileNames[i], HashCode[i]);
            }
    

    您可以将上面的代码放在您提供的函数中的 return 语句之前。然后返回字典。当然,您可以通过将它们直接存储在字典中来缩短整个函数,但我会留给您决定。

    现在,无论从何处调用此函数,您都可能需要遍历此字典。这是一种方法:

            foreach (var pair in dictionary)
            {
                string filename = pair.Key;
                string hashcode = pair.Value;
    
                // Do whatever you want with them here
            }
    

    毫无疑问,还有其他方法可以做你想做的事。我不完全确定您的总体目标是什么。您也应该尝试使用其他通用集合,例如 List&lt;T&gt;

    【讨论】:

    • 谢谢菲利普。我的应用程序应该通过比较两个文件的哈希码来识别文件是否已更改或更改。我是一名测试人员,所以每个测试周期我们都会获得可能已发布的文件,这些文件可能已更改,但背景可能已更改,或者 TC 之间的基线可能已更改。因此需要在文件名之间进行比较,如果文件相同,请检查哈希码,如果文件相同,则将其标记为绿色,如果是新文件则标记为橙色,如果文件存在但哈希不同则标记为红色。如果它对我有帮助,我会尝试并反馈:)
    【解决方案2】:

    如果 HashCode 属于一个文件,为什么它不是它的子元素/属性?这将使解析变得更容易。

    既然您创建了文件,我将创建如下结构:

    <Project Name="tfasdtyf">
        <TestCycle Number="23423">
          <Files>
            <File Name="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\DllTest.dll" HashCode="0E-C5-03-AD-CC-21-62-49-D9-36-3F-C4-F1-17-BC-11" />
            <File Name="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\WpfDllTest.exe" HashCode="60-46-A3-6F-82-E4-0A-00-2A-60-83-47-B2-16-F3-24" />
            <File Name="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\WpfDllTest.vshost.exe" HashCode="76-7B-6F-37-0D-3A-F2-F4-32-D1-70-A5-75-3B-DE-95" />
          </Files>
        </TestCycle>
    </Project>
    

    然后使用一些 XElement 魔法,您可以使用:

    public class Project
    {
        XElement self;
        public Project(XElement project)
        {
            self = project;
        }
    
        public TestCycle TestCycle
        {
            get 
            { 
                // If there are more than one TestCycle per project, you may end 
                // up creating something similar to TestCycle.Files (see TestCycle class below)
    
                XElement testCycle = self.Element("TestCycle");
                if(null == testCycle)
                    self.Add(testCycle = new XElement("TestCycle"));
                return new TestCycle(testCycle);
            }
        }
    
        public string Name
        {
             get { return return self.GetString("Name", string.Empty, ATTRIBUTE); }
             set { self.Set("Name", value, ATTRIBUTE); } // see Set Extension method below
        }
    
        public static IEnumerable<Project> Load(string filename)
        {
             return XElement.Load(filename)).Elements("Project").Select(xp => new Project(xp));
        }
    }
    
    public class TestCycle
    {
        XElement self;
        public TestCycle(XElement testCycle)
        {
            self = testCycle;
        }
    
        private XElement XFiles
        {
            get 
            {
                XElement files = self.Element("Files");
                if(null == files)
                    self.Add(files = new XElement("Files"));
                return files;
            }
        }
    
        public IEnumerable<FileHash> Files
        {
            get 
            {
                return XFiles.Elements("File").Select(xf => new FileHash(xf));
            }
        }
    
        public int Number
        {
             get { return self.GetInt("Number", 0, ATTRIBUTE); }
             set { self.Set("Number", value, ATTRIBUTE); } // see Set Extension method below
        }
    
        public FileHash AddFile(string name, string hashCode)
        {
             FileHash file = Files.FirstOrDefault(xf => xf.Name == name);
             if(null != file)
                 file.self.Remove(); // replacing (but could throw an exception saying already exists instead)
             XElement xFile = new XElement("File");
             self.Add(xFile);
             file = new FileHash(xFile)
             {
                 Name = name,
                 HashCode = hashCode
             };
             return file;
        }
    }
    
    public class FileHash
    {
        internal XElement self;
        public FileHash(XElement fileHash)
        {
            self = fileHash;
        }
    
        public string Name
        {
             get { return self.GetString("Name", string.Empty, ATTRIBUTE); }
             set { self.Set("Name", value, ATTRIBUTE); } // see Set Extension method below
        }
    
        public string HashCode
        {                 
             get { return return self.GetString("HashCode", string.Empty, ATTRIBUTE); }
             set { self.Set("HashCode", value, ATTRIBUTE); } // see Set Extension method below
        }
    }
    

    扩展方法:

    public static XElementExtensions
    {
        public const bool ATTRIBUTE = true;
        public const bool ELEMENT = false;
        public const bool? BOTH = null;
    
    public void Set(this XElement self, string name, object value, bool isAttribute)
    {
        string sValue = value.ToString();
        XElement eValue = self.Element(name);
        XAttribute aValue = self.Attribute(name);
        if(null != eValue)
            eValue.ReplaceWith(new XElement(name, sValue));
        else if(null != aValue)
            aValue.ReplaceWith(new XAttribute(name, sValue));
        else if(isAttribute)
            self.Add(new XAttribute(name, sValue));
        else
            self.Add(new XElement(name, sValue));
    }
    
    public string GetString(this XElement self, string name, string @default, bool? isAttribute)
    {
        XAttribute aValue = self.Attribute(name);
        XElement eValue = self.Element(name);
        if(null == isAttribute) // try both
        {
            if(null != aValue) return (string)aValue;
            if(null != eValue) return (string)eValue;
            return @default;
        }
        if(isAttribute && null != aValue)
            return (string)aValue;
        if(!isAttribute && null != eValue)
            return (string)eValue);
        return @default;
    }
    
    public int GetInt(this XElement self, string name, int @default, bool? isAttribute)
    {
        return Convert
            .ToInt32(GetString(self, name, null, isAttribute) ?? @default.ToString());
    }
    
    }
    

    然后你可以使用如下代码:

    Project[] projects = Project.Load(filename).ToArray();
    
    foreach(Project project in projects)
    {
        Console.WriteLine("Project: " + project.Name);
        Console.WriteLine("TestCycle: " + project.TestCycle.Number.ToString());
        Console.WriteLine("Files:");
        foreach(FileHash file in project.TestCycle.Files)
            Console.WriteLine(string.Format("    Name: {0}, HashCode: {1}", file.Name, file.HashCode));
    }
    

    或者对于您的应用程序,比较两个 xml 文件:

    var fileA = Project.Load(fileAname);
    var fileB = Project.Load(fileBname);
    

    我不太清楚你的意思,所有文件,但我会尝试一下。

    File[] filesA = fileA.SelectMany(project => project.TestCycle.Files).ToArray();
    File[] filesB = fileB.SelectMany(project => project.TestCycle.Files).ToArray();
    

    使用这些扩展方法:

    public static IEnumerable<TSource> Except<TSource>
    (
        this IEnumerable<TSource> first,
        IEnumerable<TSource> second,
        Func<TSource, TSource, bool> comparer
    )
    {
        return first.Except(second, new LambdaComparer<TSource>(comparer));
    }
    
    public static IEnumerable<TSource> Intersect<TSource>
    (
        this IEnumerable<TSource> first,
        IEnumerable<TSource> second,
        Func<TSource, TSource, bool> comparer
    )
    {
        return first.Intersect(second, new LambdaComparer<TSource>(comparer));
    }
    

    还有 LambdaComparer 类:

    public class LambdaComparer<T> : IEqualityComparer<T>
    {
        private readonly Func<T, T, bool> equals;
        private readonly Func<T, int> getHashCode;
    
        public LambdaComparer(Func<T, T, bool> lambdaComparer) :
            this(lambdaComparer, o => o.GetHashCode())
        {
        }
    
        public LambdaComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
        {
            if (lambdaComparer == null)
                throw new ArgumentNullException("lambdaComparer");
            if (lambdaHash == null)
                throw new ArgumentNullException("lambdaHash");
    
            equals = lambdaComparer;
    
            getHashCode = lambdaHash;
        }
    
        public bool Equals(T x, T y)
        {
            return equals(x, y);
        }
    
        public int GetHashCode(T obj)
        {
            return getHashCode(obj);
        }
    }
    
    File[] filesInA_butNotInB = filesA.Except(filesB, (a,b) => a.Name == b.Name).ToArray();
    File[] filesInBoth = filesA.Intersect(filesB, (a,b) => a.Name == b.Name).ToArray();
    File[] filesInBoth_butDifferentHash = FilesA.Intersect(filesB, (a,b) => a.Name == b.Name && a.HashCode != b.HashCode).ToArray();
    

    这应该“让你开始”......

    PS:我(大部分)都是手工编写的,而不是通过编译器,所以编译器可能会发现一些错字。

    PS:另外,所有.ToArray()'s 只是因为File[]IEnumerable&lt;File&gt; 更容易阅读。它更容易阅读,但无论哪种方式输入都差不多。

    PSS:我希望你觉得这很有用。我喜欢 Xml Linq 处理事情的方式,所以写出来是有趣

    【讨论】:

    • 感谢您的回答,chuck :) 这有点超出我的水平哈哈,但是我对您使用的一些东西进行一些研究,因为我以前从未见过 lambda。我会试一试,虽然它可能会解决我的很多问题。
    • 也感谢您对子元素/属性的评论,我不知道这是可能的。我可能会受到它的限制,因为我在 C++/CLI 中使用 XMLDocument 来创建 XML,然后我通过 DLL 调用函数。不是这样吗,因为我在开始使用 C# 之前就已经编写好了代码
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-13
    • 1970-01-01
    • 1970-01-01
    • 2019-04-06
    • 1970-01-01
    • 2015-10-17
    相关资源
    最近更新 更多