需要一个允许重复键的数据结构

本文关键字:许重复 数据结构 一个 | 更新日期: 2023-09-27 17:49:19

我有数据行,看起来像这样:

(汽车,颜色,年龄)例如

:

福特,红色,4
丰田,绿色,3
福特、蓝色、2

我需要遍历这些数据行,并在提交给存储过程之前执行验证。在这种情况下,如果有不止一辆相同类型的汽车,我需要确保颜色不同。所以上面的例子是允许的,但是这个例子不允许:

福特,红色,4
丰田,绿色,3
福特,红2

我如何在c#中做到这一点。我试过用字典,但它不允许重复的键。列表似乎也不是正确的选择?有人能指点一下吗?谢谢。

需要一个允许重复键的数据结构

实际上没有重复的键,您只是有一个由两个值组成的键(复合键),具体来说,您的值是汽车和颜色。因此,您需要一个表示汽车/颜色对的对象,并根据这两个值实现相等。

这意味着你不需要一个不同的数据结构,Dictionary很好,你只需要想出一个合适的类型作为字典的键。单凭一辆车或一种颜色都不能达到你想要的效果。

你可以自己写;只是一个类,具有两个属性和适当的Equals/GetHashCode覆盖,如果这是您在应用程序的多个地方或在足够大的范围内使用的东西,您应该这样做。如果你只在有限的局部范围内使用它,你可以使用Tuple<Car, Color>作为你的字典键。

如果Servy的答案不适用于您,并且您确实只是在汽车上键入了键(例如,您可能有多辆相同颜色的汽车)。

有一个内置的类型,其行为类似于ReadOnlyDictionary<Tkey, IEnumerable<TValue>>,其中可枚举对象保存碰撞,它是ILookup

最简单的方法是使用LINQ中的.ToLookup(扩展方法。

class Row
{
    public CarEnum Car {get; set;}
    public string Color {get; set;}
    public int Age {get; set;
}

void Validate(List<Row> rows)
{
   //I did not use "var" to make it more obvious what is going on, in production code I would use "var".
   ILookup<CarEnum, Row> rowLookup = rows.ToLookup((row)=>row.Car);
   foreach(IGrouping<CarEnum, Row> carKey in rowLookup)
   {
       //This loop would loop once for Ford, once for Toyota
       foreach(Row row in carKey)
       {
           //This loop would loop twice in the Ford iteration and lope once in the Toyota iteration. 
           DoValidate(row);
       }
   }
}

另一个解决方案是使用GroupBy表达式查找重复项:

public void Validate(List<Row> rows)
{
    var sameCarColorMoreThanOne = rows.GroupBy(ks => new { ks.Car, ks.Color })
                                      .Select(s => new { s.Key, Count = s.Count() })
                                      .Where(p => p.Count > 1);
    if (sameCarColorMoreThanOne.Any())
        throw new ExceptionWithListOfDuplicateKeys(sameCarColorMoreThanOne.Select(s => new Tuple<string, string>(s.Key.Car, s.Key.Color)).ToList());
}

其中ExceptionWithListOfDuplicateKeys只是一些想出的异常类型,它包含违规汽车/颜色组合的元组列表