【问题标题】:Best way to group by category a list of products | Javascript按类别对产品列表进行分组的最佳方法 | Javascript
【发布时间】:2021-08-05 05:48:51
【问题描述】:

我正在尝试找到按类别分组并在 O (n) 中迭代产品以从类别中获得一些见解的最佳方法。

我有样本数据:

[
    {
        "code": 25754,
        "description": "ADAPTADOR BLUETOOH USB RECEPTOR DE AUDIO P2",
        "price": 5.0,
        "stock": 10,
        "category": {
            "id": 1,
            "name": "Adapters"
        }
    },
    {
        "code": 20212,
        "description": "ADAPTADOR CONECTOR HDMI FEMEA L / FEMEA",
        "price": 2.8,
        "stock": 20,
        "category": {
            "id": 2,
            "name": "Eletronics"
        }
    },
]

我需要反转关系,拥有一个包含相应产品的类别列表,为此我编写了这个解决方案

function group_by_categories(products) {
    const categories = {}

    for (const product of products) {
        const { category, ...cleanedProduct } = product
        categories[category.id] = categories[category.id] || category
        categories[category.id].products = categories[category.id].products || []
        categories[category.id].products.push(cleanedProduct)
    }

    return Object.values(categories)
}

// returns

[
  { id: 1, name: 'Adapters', products: [ [Object] ] },
  { id: 2, name: 'Eletronics', products: [ [Object] ] }
]

但我在两件事上苦苦挣扎。

  1. 这是扭转关系的最佳方式吗?如何在没有对象用作唯一键的 C 等其他语言中复制它?

  2. 一旦您拥有此类数据,迭代类别和产品(例如查看一个类别有多少项目)的唯一方法是 O (n²)?

感谢所有帮助,即使您只能回答一个问题。另外,对不起我的英语不好,我在这里尽量说清楚。

【问题讨论】:

  • 您应该将问题限制在一个问题上。 “这是扭转关系的最佳方式吗?” 更适合Code Review“我怎样才能用另一种语言复制它”这个问题太宽泛了。您应该具体了解目标语言并展示您的工作以及您遇到的问题。关于时间复杂度的问题是可以的。

标签: javascript c algorithm grouping


【解决方案1】:

所以你有 3 个问题。 1) 使用代码/id 作为键,2) 使用集合而不是数组,以及 3) 使用适当的数据结构来避免重复您已经完成的工作。

  1. 您真的只想映射连接而不是所有数据。我相信代码可能是产品独有的,所以这是你的关键。您的类别 ID 也可能是唯一的,因此您只需要考虑这一点。映射结构应该只关注最少量的唯一数据。这可能会提高性能,并且复制的数据量可能是您的 1/10 到 1/100 的字符数(当然,将其准确转换为节省的时间很困难)。当然,与 O(N^2) 的性能相比,这只是一个小问题,但仅此一项就可能会加快速度。
  2. 您应该使用集合以及散列(对象)。这里的想法是O(1) 查找,O(1) 大小检查,O(1) 包含测试(IE:类别 X 中是否有代码 Y?),以及 O(1) 映射回原始数据(代码 Y 是产品与此信息)。

另一个关键是你真的只想映射连接而不是所有数据。我相信代码可能是产品独有的,所以这是你的关键。您的类别映射结构应该只关注最少量的唯一数据(这也会大大提高性能)。

请记住,如果您可以访问可能是更理想解决方案的实际数据库,那么一旦您开始想要执行更复杂的查询,95% 左右的时间。我会说你几乎肯定应该使用一个,可能有一个数据库可以满足你的需求。

话虽如此,如果您不需要对查询进行过多处理,那么您需要的是这个。看来您需要回答这三个问题:

  • 给定代码,记录是什么(样本数据)?这只是一个简单的code:product 对象。即:{25754: {code: ..., price: ..., stock: ..., ...}, {20212: {code: ..., price: ..., stock: ..., ...}}
  • 给定一个类别,该类别中的代码是什么?在这种情况下,您有一个 category_id:set(codes) 查找。将代码添加到集合而不是列表/数组非常重要。集合有O(1) 可以添加/删除/包含,而列表/数组有O(1) 添加、O(N) 删除和O(N) 包含检查。
  • 给定一个类别,该类别中有多少个?这只是一个data[category].size 检查(在某些语言中是长度而不是大小)。

主要是使用字典和集合来提高性能。

构建查找的时间可能是O(P),其中P 是产品总数。对于您需要执行的每个查询,查询的性能应该是O(1)

为了避免O(N^2) 的性能,查找应该只计算一次。如果您需要从类别中添加/删除产品,您应该调整查找本身,而不是每次都重新构建它。这可能意味着将其存储在数据库中,在您首次运行应用程序时构建并将其保存在内存中,或者如果产品数量不是太多,则在每次请求时构建它(仅使用最少量的数据来构建它,它可能更实用)。一般来说,即使有 1000 种产品,构建类别查找并对其进行迭代也可能需要几毫秒的时间。

在你写出方法之后,你的类别代码基本上应该看起来像他的。

...
category_lookup = build_category_lookup() # O(P)
product_lookup = build_product_lookup() # O(P)
...
products_for_category = product_lookup[category_id] # O(1)
products_count = products_for_category.length # O(1) | C: sizeof(products_for_category)
...

(现在主要是用 ruby​​ 编写代码,所以snake_case

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-03
    • 1970-01-01
    • 2018-12-10
    • 2017-01-26
    • 2010-10-16
    • 2010-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多