You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:26:46