C # Хранение нескольких элементов в нескольких массивах для сравнения - PullRequest
0 голосов
/ 22 июля 2011

У меня есть приложение, которое читает имена файлов и их эквивалентные хэш-коды из XML (после того, как я создал XML, используя то же приложение), и я хотел бы сравнить это один XML (файлы и их хеш-коды) в другой XML (возможно, с другими файлами и хэш-кодами).Я пытаюсь создать функцию сравнения, чтобы я мог сначала сравнить имена файлов между двумя XML-файлами, а затем сравнить хэш-коды, если файлы существуют в обоих XML-файлах.

(чтобы понять, что я пытаюсь достичь, у меня есть 2 списка рядом друг с другом, по одному для каждого xmls. После того, как я их сравню, я хочу, чтобы оба списка заполнились всеми именами файлов, но не хеш-кодамиа затем пометить их разными цветами в зависимости от того, являются ли они одним и тем же файлом, тем же файлом, но другим содержимым, или этот файл вообще не существует в другом 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 функции, подобные приведенной выше, для каждого набора имен файлов, а затем для каждого набора хеш-кодов.Но я все еще начинающий, так что, может быть, это мой лучший вариант?

Ответы [ 2 ]

1 голос
/ 23 июля 2011

Если 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, так что это было забавно писать это.

1 голос
/ 22 июля 2011

Лучше не дублировать функцию . Вы хотите создать одну функцию, которую можно использовать во всех ваших случаях здесь.

Что касается хранения имен файлов и хэш-кодов, в .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]);
        }

Приведенный выше код вы можете поместить прямо перед оператором return в предоставленной вами функции. Затем верните словарь. Конечно, вы можете сделать всю функцию короче, сохранив их непосредственно в словаре, но я оставлю это на ваше усмотрение.

Теперь, откуда бы эта функция ни вызывалась, вам может понадобиться пройтись по этому словарю. Вот способ сделать это:

        foreach (var pair in dictionary)
        {
            string filename = pair.Key;
            string hashcode = pair.Value;

            // Do whatever you want with them here
        }

Без сомнения, есть и другие способы делать то, что вы хотите. Я не совсем уверен, какова ваша общая цель. Вам также следует поэкспериментировать с другими общими коллекциями, такими как List<T>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...