在多个数组中存储多个项以进行比较
本文关键字:比较 存储 数组 | 更新日期: 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处理事情的方式,所以写出来很有趣