开发者

C# Comparing 4 String arrays

开发者 https://www.devze.com 2023-03-22 19:34 出处:网络
I\'m trying to compare four arrays. Two of the four arrays store filenames, while the other two arrays store hashcodes.

I'm trying to compare four arrays. Two of the four arrays store filenames, while the other two arrays store hashcodes.

One of the arrays storing file names is related to one of the arrays storing hashcodes, these hashcodes are for the file in the file name array.

So for example I have two projects ProjectOne and ProjectTwo. ProjectOne is a combination of an array called ProjectOneFiles and an array of ProjectOneHashcodes. Both those arrays will always be of the same length.

ProjectTwo will be a combination of an array called ProjectTwoFiles and an array of ProjectTwoHashcodes. Both those arrays will also always be of the same length.

However ProjectOne won't necessarily be the same length as ProjectTwo. This is what I currently have:

private void Compare()
{
    String[] ProjectOneFiles = ProjOneFiles();
    String[] ProjectTwoFiles = ProjTwoFiles();
    String[] ProjectOneHash = ProjOneHash();
    String[] ProjectTwoHash = ProjTwoHash();

    for (int x = 0; x < ProjectOneFiles.length; ++x)
    {
        String Test1 = ProjectOneFiles[x];
        String Test2 = ProjectTwoFiles[x];
        String Test3 = ProjectOneHash[x];
        String Test4 = ProjectTwoHash[x];

        if (Test1 != Test2)
        {
            listBox6.Items.Add(Test1);
            listBox6.Items.Add(Test2);
        }
        else if ((Test1 == Test2) && (Test3 == Test4))
        {
            listBox7.Items.Add(Test1);
        }
        else
        {
            listBox8.Items.Add(Test1);
        }
    }
}

Obviously now my problem appears where I have two of the four arrays not being the same length. If I try to iterate through and I'm using the smallest array size therefore I wont iterate through the largest array completely.

If I try to iterate through an array which, lets say, has five items, one hundred times obviously I get an out of range exception.

I need to compare the two file name arrays first and then if they are the same compare the two hashcode arrays. If they meet certain requirements they need to be put in one of three lists and all three lists could possibly be filled.

I would have liked to have done it in LINQ:

    var onlyinfirst = 
        from s in ProjectOneFiles 
        where !ProjectTwoFiles.Contains(s) && 
              (ProjectOneHash.Contains(p) == ProjectTwoHash.Contains(p))
        select s;

    var onlyinsecond = 
        from s in ProjectTwoFiles 
        where !ProjectOneFiles.Contains(s) 
        select s;

    var onboth = 
        from s in ProjectOneFiles 
        where ProjectTwoFiles.Contains(s) 
        select s;

However I got stuck doing it that way because I'm not sure how to do nested statements to remove my if statements. As you can see in my first line I tried to do just that but im completely stuck using it now. Both the filename array and the hashcode array are related so the LINQ statement has to be in a single pass otherwise the hashcode will no longer correlate (index wise) to the file name.

A lot of my issues may be solved with using a multidimensional array but I find them very confusing and i would rather not have to go rewrite my functions to work with them.

Extra Info and functions to help explain:

In case someone needs this information to help answer my question, the filenames and arrays are pulled from an XML document like this:

<?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\DllTest1.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-25" />
        <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="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>

I then have four functions similar to the one below that pull the the filenames and hashcodes for the projects and that's how I get each of the arrays:

private String[] ProjOneFiles()
{
    //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];

    int y = 0;

    //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"))
            {

                FileNames[y] = Nav.Value;
                //listBox4.Items.Add(Nav.Value);
                y = y + 1;
            }
        }
    }
    return FileNames;
}

private String[] ProjOneHash()
{
    //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 = NumXM开发者_运维问答LItemsListOne();

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

    int z = 0;

    //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/HashCode/@Code"))
            {
                HashCode[z] = Nav.Value;
                //listBox4.Items.Add(Nav.Value);
                z = z + 1;
            }
        }
    }
    return HashCode;
}


The simple but not particularly elegant way:

private void Compare()
    {
        String[] ProjectOneFiles = ProjOneFiles();
        String[] ProjectTwoFiles = ProjTwoFiles();
        String[] ProjectOneHash = ProjOneHash();
        String[] ProjectTwoHash = ProjTwoHash();

        for (int x = 0; x < ProjectOneFiles.length || x < ProjectTwoFiles.length; ++x)
        {
            String Test1 = x < ProjectOneFiles.length ? ProjectOneFiles[x] : "";
            String Test2 = x < ProjectTwoFiles.length ? ProjectTwoFiles[x] : "";
            String Test3 = x < ProjectOneFiles.length ? ProjectOneHash[x] : "";
            String Test4 = x < ProjectTwoFiles.length ? ProjectTwoHash[x] : "";

            if (Test1.CompareTo(Test2) != 0)
            {
                listBox6.Items.Add(Test1);
                listBox6.Items.Add(Test2);
            }
            else if (Test3.CompareTo(Test4) == 0)
            {
                listBox7.Items.Add(Test1);
            }
            else
            {
                listBox8.Items.Add(Test1);
            }
        }
    }


To elaborate on the Dictionary approach mentioned above, you might consider something like: Dictionary hashDic = new Dictionary();

for(int i = 0; i < ProjectOneFiles.Length; i++)
{
    //Add to the dictionary using hashDic.Add(FILENAME_HERE, HASH_HERE).
}

for(int i = 0; i < ProjectTwoFiles.Length; i++)
{
    string projectOneValue;
    if(hashDic.TryGetValue(ProjectTwoFiles[i], out projectOneValue))
    {
        //If this code executes, you'll know that the file is in both projects.
        //The hash for the file in project one is in "projectOneValue."
        //The hash for the file in project two is in "ProjectTwoHash[i]".

        //You can remove this entry from the dictionary using
        //hashDic.Remove(FILE_NAME_HERE)
    }
    else
    {
        //If this code executes, then this file is only in ProjectTwo.
    }
}

//This loop will loop over all the files that are ONLY in ProjectOne.
foreach(KeyValuePair<string, string> kvp in hashDic)
{
    //kvp.Key is the filename.
    //kvp.Value is the hash.
    //For every pass of this loop you'll be looking at a different
    //file/hash that is ONLY in project one.
}


Admittedly, I skipped over some of the stuff at the end, but how does this work for you?

I'm not sure precisely where you're getting stuck, but it seems like you just need a hand figuring out which items are unique and which items are not unique to each list.

In that case, this should help:

var onlyInListOne = ProjectOneFiles.Except(ProjectTwoFiles);
var onlyInListTwo = ProjectTwoFiles.Except(ProjectOneFiles);
var inBothLists = ProjectOneFiles.Intersect(ProjectTwoFiles);

I used the "var" keyword to save typing, but the actual data type that is going to get spit out of the LINQ statement is IEnumerable. If you need it to be a List you can just call .ToList() at the end of the line, like so:

var onlyInListOne = ProjectOneFiles.Except(ProjectTwoFiles).ToList();
var onlyInListTwo = ProjectTwoFiles.Except(ProjectOneFiles).ToList();
var inBothLists = ProjectOneFiles.Intersect(ProjectTwoFiles).ToList();

Generally speaking, though--ToList() isn't the fastest method on the planet so while its sometimes necessary, if you really don't need List objects, I'd avoid it.

.Except(...) just takes all of the strings in one list and excludes any of them that are also in the other list. .Intersect(...) finds only the files that are in both lists.

If there's something else in particular that I missed, let me know in a comment and I'll see if I can help out.


Try this.

private void Compare()
{
    String[] ProjectOneFiles = ProjOneFiles();
    String[] ProjectTwoFiles = ProjTwoFiles();
    String[] ProjectOneHash = ProjOneHash();
    String[] ProjectTwoHash = ProjTwoHash();

    //make project one the greater of the two always
    if (ProjectTwoFiles.Length > ProjectTwoFiles.Length)
    {
        Swap(ref ProjectOneFiles, ref ProjectTwoFiles);
        Swap(ref ProjectOneHash, ref ProjectTwoHash);
    }

    for (int x = 0; x < ProjectTwoFiles.length; x++)
    {
        String Test1 = ProjectOneFiles[x];
        String Test2 = ProjectTwoFiles[x];
        String Test3 = ProjectOneHash[x];
        String Test4 = ProjectTwoHash[x];

        if (Test1 != Test2)
        {
            listBox6.Items.Add(Test1);
            listBox6.Items.Add(Test2);
        }
        else if ((Test1 == Test2) && (Test3 == Test4))
        {
            listBox7.Items.Add(Test1);
        }
        else
        {
            listBox8.Items.Add(Test1);
        }
    }
    for (int x = ProjectTwoFiles.Length + 1; x < ProjectOneFiles.length; x++)
    {
        //add to some other list
    }
}

private static void Swap(ref string[] foo, ref string[] bar)
{
    string[] tmp = foo;
    foo = bar;
    bar = tmp;
}

The trick is to make ProjectOne the bigger array by swapping. Now all operations are easy as you can always predict the bigger array.

Disclaimer: This just solves your issue. It is not optimised at all.
Could start optimising from changing DevelopSomalia() to DevelopCountry("Somalia")

0

精彩评论

暂无评论...
验证码 换一张
取 消