假设我有一个对象列表,对象Fruit
。水果有一个性质Name
。即Fruit1.Name = "Apple"
, Fruit2.Name = "Orange"
, Fruit3.Name = "Apple"
, Fruit4.Name = "Melon"
…等
List<Fruit> Basket = {Fruit1, Fruit2, Fruit3, Fruit4, Fruit 5...... Fruit 100}.
我想有一个唯一水果列表,其中列表中的每个水果都有唯一的名称。我想优化时间。我见过一些人这样做。这是最好的方法吗?
public List<Fruit> GetUniqueFruits(List<Fruit> Basket)
{
Dictionary<string, Fruit> tempUniqueFruits = new Dictionary<string, Fruit>();
List<Fruit> uniqueFruits = new List<Fruit>();
foreach(var fruit in Basket)
{
if (!tempUniqueFruits.ContainsKey(fruit.Name)
{
tempUniqueFruits.Add(fruit.Name, fruit);
uniqueFruits.Add(fruit);
}
}
return uniqueFruits;
}
我听说字典查找非常快,所以我想这可能就是为什么要使用这个,但是我想知道是否有更好的方法。
谢谢matt burland,我改正了错字。(还不能评论)您可以使用IEqualityComparer
来澄清代码。
public List<Fruit> GetUniqueFruits(List<Fruit> Basket) {
var set = new HashSet<Fruit>(Basket, new FruitNameEqualityComparer());
return set.ToList();
}
public class Fruit {
public string Name { get; set; }
public DateTime RipeTime { get; set; }
}
class FruitNameEqualityComparer : IEqualityComparer<Fruit> {
public int Compare(Fruit a, Fruit b) {
return a.Name.CompareTo(b.Name);
}
public bool Equals(Fruit a, Fruit b) {
return a.Name.Equals(b.Name);
}
public int GetHashCode(Fruit f) {
return f.Name.GetHashCode();
}
}
Dictionary<T, U>
最好用于从键到值的映射,但如果您只对维护一组惟一值感兴趣,而不需要任何映射,则HashSet<T>
是专门为该目的设计的。
字典强制代码确保它只包含唯一的键,而不是值。所以如果你尝试添加另一个已经存在的键,它会抛出一个错误。当你想要获取一个值时,你只需要通过键名来获取它,字典会使用散列进行查找,这使得它非常非常快。当你想要搜索列表时,你必须遍历整个列表来找到你想要的那个,这可能很慢,因为你要遍历整个列表。
更短的方式是:
return Basket.GroupBy(f => f.Name).Select(grp => grp.First()).ToList();
尽管这可能不会保留Basket
中给定名称的第一项
因此,如果名称是对象的唯一部分(即键),并且项目的顺序并不重要,那么Dictionary<string, Fruit>
是存储它们的完全有效的方法。另一个选择是HashSet
,但是你需要在你的Fruit
类中实现Equals
和GetHashCode
(或创建IEqualityComparer<Fruit>
)。
但是对于你的特定代码,你可以使用Linq语句(像Lee的),这是有效的,但是对于你的特定代码,你不需要在创建字典的同时创建一个唯一项的列表(除非顺序很重要),因为你可以返回tempUniqueFruits.Values.ToList()
另外,如果您想构建唯一项的列表(以保持顺序),那么由于您实际上不使用字典中的值,而只是使用键,因此您可以使用HashSet<string>
代替。