在多个数组中存储多个项以进行比较

本文关键字:比较 存储 数组 | 更新日期: 2023-09-27 18:03:24

我有一个应用程序,读取文件名和它们等效的哈希码从XML(之后我已经创建了使用相同的应用程序的XML)和我想要做的是比较一个XML(文件和它们的哈希码)到另一个XML(可能不同的文件和哈希码)。我试图创建一个比较函数,以便我可以比较文件名,首先,在两个xml之间,然后比较哈希码,如果文件存在于两个xml中。

(为了帮助理解我想要实现什么,基本上我有两个列表框彼此相邻,一个用于每个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>

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

2D数组让我很困惑,我不确定我如何从他们那里得到我需要的信息,当它归结为我需要做的比较。有谁能告诉我更好的方法吗?

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

在多个数组中存储多个项以进行比较

最好不要复制函数。你想要一个可以在这里的所有情况下使用的单一函数。

至于存储文件名和哈希码,. net有很多有用的集合类可供使用。例如,您可以像这样使用Dictionary<string, string>:

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

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

现在,无论从哪里调用这个函数,都可能需要循环遍历这个字典。这里有一个方法:

        foreach (var pair in dictionary)
        {
            string filename = pair.Key;
            string hashcode = pair.Value;
            // Do whatever you want with them here
        }
毫无疑问,还有其他方法可以做你想做的事。我不完全确定你的总体目标是什么。您还应该尝试其他泛型集合,例如List<T>

如果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<File>更容易阅读。它更容易阅读,但两种方式的输入都是一样的。

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