C# 从结构的数组中删除重复项
我无法从结构数组中删除重复项 我有这个结构:C# 从结构的数组中删除重复项,c#,.net,c#-4.0,C#,.net,C# 4.0,我无法从结构数组中删除重复项 我有这个结构: public struct stAppInfo { public string sTitle; public string sRelativePath; public string sCmdLine; public bool bFindInstalled; public string sFindTitle; public string sFindVersion; public bool bChe
public struct stAppInfo
{
public string sTitle;
public string sRelativePath;
public string sCmdLine;
public bool bFindInstalled;
public string sFindTitle;
public string sFindVersion;
public bool bChecked;
}
由于Jon Skeet
代码如下:(短版本)
我需要appInfo数组在sTitle和sRelativePath成员中唯一,其他成员可以重复
编辑:
感谢所有人的回答,但这个应用程序是“可移植的”,我的意思是我只需要.exe文件,我不想添加其他文件,如references*.dll,所以请不要外部引用这个应用程序是打算在pendrive中使用
所有数据都来自一个*.ini文件,我所做的是:(伪代码)
当我想将数据保存到文件中时,我有以下选项:
非常感谢:乔恩·斯基特,迈克尔·海斯谢谢你们的时间伙计们 使用LINQ2对象,按应唯一的对象分组,然后选择每组中的第一项
var noDupes = appInfo.GroupBy(
x => new { x.sTitle, x.sRelativePath })
.Select(g => g.First()).ToArray();
使用LINQ2对象,按应唯一的对象分组,然后选择每组中的第一项
var noDupes = appInfo.GroupBy(
x => new { x.sTitle, x.sRelativePath })
.Select(g => g.First()).ToArray();
首先,请不要使用可变结构。从各方面来说,它们都是个坏主意
其次,请不要使用公共字段。字段应该是实现详细信息-使用属性
第三,我根本不清楚这是否应该是一个结构。它看起来相当大,并不是特别的“单一值”
第四,请遵循以下步骤,以便您的代码与.NET中编写的所有其他代码相匹配
第五,不能从数组中删除项,因为数组是用固定大小创建的。。。但是您可以创建一个只包含唯一元素的新数组
LINQ to Objects将允许您使用Albin所示的方法来实现这一点,但在我看来,更简洁的方法是从以下位置使用:
这通常比GroupBy更高效,在我看来也更优雅
就个人而言,我通常更喜欢使用List
而不是数组,但上面的内容将为您创建一个数组
注意,在这段代码中,仍然可以有两个项目具有相同的标题,并且仍然可以有两个项目具有相同的相对路径-只是不能有两个项目具有相同的相对路径和标题。如果存在重复项,DistinctBy
将始终从输入序列中生成第一个此类项
编辑:为了满足Michael的要求,您实际上不需要先创建数组,如果不需要,也不需要再创建数组:
var query = listView1.Items
.Cast<ListViewItem>()
.Select(item => new stAppInfo
{
sTitle = item.Text,
sRelativePath = item.SubItems[1].Text,
bFindInstalled = item.SubItems[3].Text == "Sí",
sFindTitle = item.SubItems[4].Text,
sFindVersion = item.SubItems[5].Text,
bChecked = item.SubItems[6].Text == "Sí"
})
.DistinctBy(x => new { x.sTitle, x.sRelativePath });
var query=listView1.Items
.Cast()
.选择(项目=>new stAppInfo
{
针=项目。文本,
sRelativePath=item.SubItems[1]。文本,
bfininstalled=item.SubItems[3]。Text==“Sí”,
sFindTitle=item.SubItems[4]。文本,
sFindVersion=item.SubItems[5]。文本,
b检查=项。子项[6]。文本==“Sí”
})
.DistinctBy(x=>new{x.sTitle,x.sRelativePath});
这将为您提供一个延迟流化的IEnumerable
。请注意,如果您对它进行多次迭代,它将在listView1.Items
上迭代相同的次数,每次执行相同的唯一性比较
与Michael的方法相比,我更喜欢这种方法,因为它使“distinct by”列的语义非常清晰,并且消除了用于从ListViewItem
中提取这些列的代码的重复。是的,它涉及到构建更多的对象,但我更喜欢清晰而不是效率,直到基准测试证明实际上需要更高效的代码 首先,请不要使用可变结构。从各方面来说,它们都是个坏主意
其次,请不要使用公共字段。字段应该是实现详细信息-使用属性
第三,我根本不清楚这是否应该是一个结构。它看起来相当大,并不是特别的“单一值”
第四,请遵循以下步骤,以便您的代码与.NET中编写的所有其他代码相匹配
第五,不能从数组中删除项,因为数组是用固定大小创建的。。。但是您可以创建一个只包含唯一元素的新数组
LINQ to Objects将允许您使用Albin所示的方法来实现这一点,但在我看来,更简洁的方法是从以下位置使用:
这通常比GroupBy更高效,在我看来也更优雅
就个人而言,我通常更喜欢使用List
而不是数组,但上面的内容将为您创建一个数组
注意,在这段代码中,仍然可以有两个项目具有相同的标题,并且仍然可以有两个项目具有相同的相对路径-只是不能有两个项目具有相同的相对路径和标题。如果存在重复项,DistinctBy
将始终从输入序列中生成第一个此类项
编辑:为了满足Michael的要求,您实际上不需要先创建数组,如果不需要,也不需要再创建数组:
var query = listView1.Items
.Cast<ListViewItem>()
.Select(item => new stAppInfo
{
sTitle = item.Text,
sRelativePath = item.SubItems[1].Text,
bFindInstalled = item.SubItems[3].Text == "Sí",
sFindTitle = item.SubItems[4].Text,
sFindVersion = item.SubItems[5].Text,
bChecked = item.SubItems[6].Text == "Sí"
})
.DistinctBy(x => new { x.sTitle, x.sRelativePath });
var query=listView1.Items
.Cast()
.选择(项目=>new stAppInfo
{
针=项目。文本,
sRelativePath=item.SubItems[1]。文本,
bfininstalled=item.SubItems[3]。Text==“Sí”,
sFindTitle=item.SubItems[4]。文本,
sFindVersion=item.SubItems[5]。文本,
var query = listView1.Items
.Cast<ListViewItem>()
.Select(item => new stAppInfo
{
sTitle = item.Text,
sRelativePath = item.SubItems[1].Text,
bFindInstalled = item.SubItems[3].Text == "Sí",
sFindTitle = item.SubItems[4].Text,
sFindVersion = item.SubItems[5].Text,
bChecked = item.SubItems[6].Text == "Sí"
})
.DistinctBy(x => new { x.sTitle, x.sRelativePath });
public class AppInfoComparer : IEqualityComparer<stAppInfo>
{
public bool Equals(stAppInfo x, stAppInfo y) {
if (ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
return Equals(x.sTitle, y.sTitle) && Equals(x.sRelativePath,
y.sRelativePath);
}
// this part is a pain, but this one is already written
// specifically for your question.
public int GetHashCode(stAppInfo obj) {
unchecked {
return ((obj.sTitle != null
? obj.sTitle.GetHashCode() : 0) * 397)
^ (obj.sRelativePath != null
? obj.sRelativePath.GetHashCode() : 0);
}
}
}
var appInfoSet = new HashSet<stAppInfo>(new AppInfoComparer());
foreach (ListViewItem item in listView1.Items)
{
var newItem = new stAppInfo {
sTitle = item.Text,
sRelativePath = item.SubItems[1].Text,
sCmdLine = item.SubItems[2].Text,
bFindInstalled = (item.SubItems[3].Text.Equals("Sí")) ? true : false,
sFindTitle = item.SubItems[4].Text,
sFindVersion = item.SubItems[5].Text,
bChecked = (item.SubItems[6].Text.Equals("Sí")) ? true : false};
appInfoSet.Add(newItem);
}
stAppInfo[] appInfo = appInfoSet.ToArray();
private class AppInfoComparer : IComparer<stAppInfo>
{
// return -1 if x < y, 1 if x > y, or 0 if they are equal
public int Compare(stAppInfo x, stAppInfo y)
{
var comparison = x.sTitle.CompareTo(y.sTitle);
if (comparison != 0) return comparison;
return x.sRelativePath.CompareTo(y.sRelativePath);
}
}
var appInfoSet = new SortedSet<stAppInfo>(new AppInfoComparer());