如何高效实现Book对象集合的增删查(保证Id与Title唯一)
实现Book集合的O(1)增删查(保证Id与Title唯一性)
针对你的需求,同时维护两个字典是性能最优的解决方案——一个以Id为键的Dictionary<int, Book>,另一个以Title为键的Dictionary<string, Book>。这种方案既能让你以O(1)时间复杂度按Id或Title查询书籍,新增/删除时也能在O(1)内完成唯一性校验,完美解决你现在遍历校验Title效率低下的问题。
为什么不选单独的HashSet存Title?
用HashSet<string>存Title确实能快速校验唯一性,但如果要通过Title查询对应的Book,你还是得遍历主字典的所有值,做不到O(1)的查询效率。而双字典的方式,不管是按Id找Book,还是按Title找Book,都是直接的键值对查找,完全匹配你的核心诉求。
完整实现示例
我给你写一个封装好的仓库类,处理所有增删查逻辑,同时保证两个字典的一致性:
public class BookRepository { // 按Id索引的字典,保证Id唯一 private readonly Dictionary<int, Book> _booksById = new Dictionary<int, Book>(); // 按Title索引的字典,保证Title唯一 private readonly Dictionary<string, Book> _booksByTitle = new Dictionary<string, Book>(); /// <summary> /// 新增书籍,返回是否新增成功(Id或Title重复则失败) /// </summary> public bool AddBook(Book book) { // 先做唯一性校验,O(1)时间完成 if (_booksById.ContainsKey(book.Id) || _booksByTitle.ContainsKey(book.Title)) { return false; } // 两个字典同步添加 _booksById.Add(book.Id, book); _booksByTitle.Add(book.Title, book); return true; } /// <summary> /// 按Id查询书籍,不存在则返回null /// </summary> public Book GetBookById(int id) { _booksById.TryGetValue(id, out var book); return book; } /// <summary> /// 按Title查询书籍,不存在则返回null /// </summary> public Book GetBookByTitle(string title) { _booksByTitle.TryGetValue(title, out var book); return book; } /// <summary> /// 按Id删除书籍,返回是否删除成功 /// </summary> public bool DeleteBook(int id) { if (_booksById.TryGetValue(id, out var targetBook)) { // 同步删除两个字典中的条目 _booksById.Remove(id); _booksByTitle.Remove(targetBook.Title); return true; } return false; } /// <summary> /// 更新书籍的Title(额外处理:避免Title重复) /// </summary> public bool UpdateBookTitle(int bookId, string newTitle) { if (!_booksById.TryGetValue(bookId, out var targetBook)) return false; // 新Title不能和现有重复 if (_booksByTitle.ContainsKey(newTitle)) return false; // 先移除旧Title的映射,再添加新的 _booksByTitle.Remove(targetBook.Title); targetBook.Title = newTitle; _booksByTitle.Add(newTitle, targetBook); return true; } }
关键注意事项
- 一致性优先:所有增、删、改操作必须同时操作两个字典,绝对不能只修改其中一个,否则会出现数据不一致的情况(比如Id存在但Title找不到,或者反之)。
- Title大小写处理:如果你的业务场景中Title是大小写不敏感的(比如"Harry Potter"和"harry potter"视为同一本书),可以在存入和查询时统一转成小写(或大写),例如:
_booksByTitle.Add(book.Title.ToLowerInvariant(), book),查询时也用title.ToLowerInvariant()作为键。 - 线程安全:如果是多线程环境下使用,建议把普通
Dictionary换成ConcurrentDictionary,或者在操作字典时加锁,避免并发操作导致的异常或数据错乱。
内容的提问来源于stack exchange,提问作者Mhd
相关产品推荐
相关产品推荐

