检查集合c#中是不是存在元素
Posted
技术标签:
【中文标题】检查集合c#中是不是存在元素【英文标题】:Check for existence of an element in the collection c#检查集合c#中是否存在元素 【发布时间】:2021-05-05 04:12:29 【问题描述】:我试图阻止在列表中添加 C# 中已存在的项目。下面的代码循环遍历数据表行。
如您所见, rows 的类型为 List<CubeReportRow>
数据表行确实包含重复项。我需要检查数据表中的 rowName 是否已经在 List<CubeReportRow>
类型的行对象中。请查看我在 foreach 循环中设置的条件。当我尝试按行名检查时,它说无法将字符串转换为 CubeReportRow 类型。如果我检查 if (!rows.Contains(row[0])),没有编译错误,但我不工作。如何检查它是否存在于 rows 集合中。
类 CubeReportRow
public class CubeReportRow
public string RowName get; set;
public string RowParagraph get; set;
public int ReportSection get; set;
C#方法
public virtual IList<CubeReportRow> TransformResults(CubeReport report,DataTable dataTable)
if (dataTable.Rows.Count == 0 || dataTable.Columns.Count == 0)
return new List<CubeReportRow>();
var rows = new List<CubeReportRow>();
var columns = columnTransformer.GetColumns(dataTable);
foreach (DataRow row in dataTable.Rows)
var rowName = row[0].ToString();
if (!rows.Contains(rowName))
var values =
cubeReportValueFactory.CreateCubeReportValuesForRow(dataTable, row, rowName, columns, report);
var reportRow = new CubeReportRow(row[3].ToString(), row[2].ToString(), row[1].ToString(), values);
rows.Add(reportRow);
return rows;
【问题讨论】:
查看IEqualityComparer<T>
以获得您的CubeReportRow
。具有相同的RowName
属性值是否具有 Equals 的语义
【参考方案1】:
您可以将Dictionary<string, CubeReportRow>
用于您的rows
变量,并使用ContainsKey
检查密钥(rowName
)是否存在:
var rows = new Dictionary<string, CubeReportRow>();
if (!rows.ContainsKey(rowName))
// ...
rows.Add(rowName, reportRow);
// ...
return rows.Values.ToList();
【讨论】:
唯一的问题是在这种情况下您将获得后进,而使用! contains
您将获得先入。
如果你检查一个集合是否包含一个属性,那么第一个被添加,随后的则不被添加。如果你使用字典,多次添加相同的键会覆盖第一个值,所以你会得到最后一个。
@Zer0 好点,所以也许这毕竟是最好的解决方案:)
@zaitsman 是的,我撤回了我的评论,因为TryAdd
没有价值就无法工作,如果密钥存在,OP 将跳过价值创造。我只是有肌肉记忆可以发现Contains
,然后是Add
。此答案还考虑了性能。
@zaitsman 逻辑相同 - 使用 ContainsKey
检查是否存在具有相同 rowName
的内容 - 如果不存在 - 添加新内容,因此结果应该相同。跨度>
【参考方案2】:
这不是一个真正的答案,因为我相信Guru Strons 的答案就足够了。
但是,有很多方法可以做到这一点,这将产生不同的性能和复杂性,具体取决于您的数据/重复率(并且不限于以下)。
字典
var rows = new Dictionary<string, CubeReportRow>();
foreach (var dataRow in _data)
if (!rows.ContainsKey(dataRow.RowName))
rows.Add(dataRow.RowName, dataRow);
return rows.Values.ToList();
哈希集
var hashSet = new HashSet<string>(_data.Length);
return _data.Where(x => hashSet.Add(x.RowName)).ToList();
分组方式
return _data.GroupBy(x => x.RowName).Select(x => x.First()).ToList();
IEqualityComparer
public class SomeComparer : IEqualityComparer<CubeReportRow>
public bool Equals(CubeReportRow x, CubeReportRow y)
return x.RowName == y.RowName;
public int GetHashCode(CubeReportRow obj)
return obj.RowName.GetHashCode();
...
return _data.Distinct(new SomeComparer()).ToList();
基准测试
配置
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.746 (2004/?/20H1)
Intel Core i7-7700 CPU 3.60GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=5.0.102
[Host] : .NET Core 5.0.2 (CoreCLR 5.0.220.61120, CoreFX 5.0.220.61120), X64 RyuJIT
.NET Core 5.0 : .NET Core 5.0.2 (CoreCLR 5.0.220.61120, CoreFX 5.0.220.61120), X64 RyuJIT
Job=.NET Core 5.0 Runtime=.NET Core 5.0
结果
Method | Mean | Error | StdDev |
---|---|---|---|
Dictionary | 205.3 us | 4.06 us | 5.69 us |
HashSet | 237.6 us | 4.73 us | 10.19 us |
Distinct | 299.4 us | 5.24 us | 4.90 us |
GroupBy | 451.3 us | 5.28 us | 4.68 us |
完整的测试代码
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
public class Test
private CubeReportRow[] _data;
public class CubeReportRow
public string RowName get; set;
public string RowParagraph get; set;
public int ReportSection get; set;
[GlobalSetup]
public void Setup()
var r = new Random(32);
_data = new CubeReportRow[10000];
for (int i = 0; i < 10000; i++)
_data[i] = new CubeReportRow() RowName = r.Next(100).ToString();
[Benchmark]
public List<CubeReportRow> Dictionary()
var rows = new Dictionary<string, CubeReportRow>();
foreach (var dataRow in _data)
if (!rows.ContainsKey(dataRow.RowName))
rows.Add(dataRow.RowName, dataRow);
return rows.Values.ToList();
[Benchmark]
public List<CubeReportRow> HashSet()
var hashSet = new HashSet<string>(_data.Length);
return _data.Where(x => hashSet.Add(x.RowName)).ToList();
public class SomeComparer : IEqualityComparer<CubeReportRow>
public bool Equals(CubeReportRow x, CubeReportRow y)
return x.RowName == y.RowName;
public int GetHashCode(CubeReportRow obj)
return obj.RowName.GetHashCode();
[Benchmark]
public List<CubeReportRow> Distinct()
return _data.Distinct(new SomeComparer()).ToList();
[Benchmark]
public List<CubeReportRow> GroupBy()
return _data.GroupBy(x => x.RowName).Select(x => x.First()).ToList();
注意:如果您对性能感兴趣,请使用真实数据自行运行这些基准测试。
【讨论】:
【参考方案3】:LINQ 非常适合这一点(就易于阅读的代码而言)
在文件顶部:
using System.Linq;
然后:
if (!rows.Any(r => r.RowName == rowName))
(替换if (!rows.Contains(rowName))
)
【讨论】:
@GuruStron 不:docs.microsoft.com/en-us/dotnet/api/… 他的返回类型是IList
,他没有提到LINQ
。无论如何,您链接的 Contains 需要传入一个完整的对象,并将使用 .Equals()
进行评估,但 OP 需要的是通过他的数据行中的第一列进行比较。
我在 r[0] 行遇到错误。无法将索引应用于 CubeReportRow 类型的表达式
@Tom 道歉,改成r.RowName
(见我的编辑)
如果 (!rows.Any(r => r.RowName == rowName)) 可能是这样的以上是关于检查集合c#中是不是存在元素的主要内容,如果未能解决你的问题,请参考以下文章
C#日常C#泛型集合Dictionary<TKey, TValue>使用方法及泛型集合检查是否存在Key值
C#日常C#泛型集合Dictionary<TKey, TValue>使用方法及泛型集合检查是否存在Key值