如何在Swift 5中按键属性从字典中查找总计

如何在Swift 5中按键属性从字典中查找总计,swift,Swift,如何从[Product:Double]的字典中找到品牌的总计 产品具有属性品牌 let items = [Item] let productTotals = items.reduce([Product:Double()) {(result, item in var result = result let product = item.product // Calculate the total product width result[product] = product

如何从
[Product:Double]
的字典中找到
品牌的总计

产品
具有属性
品牌

let items = [Item]

let productTotals = items.reduce([Product:Double()) {(result, item in 

  var result = result
  let product = item.product

  // Calculate the total product width
  result[product] = product.width * item.count

  return result
}

// Now find the totals for each brand by summing the values for Product.brand
let groupTotals = productTotals ???
范例

items = [{ix = 1, product = A, count = 1}, {ix = 2, product = B, count = 2}, {ix = 3, product = C, count = 2}]

products = [{name = 'A', width = 1.0, brand = 'BA'}, {name = 'B', width = 2.0, brand = 'BA'}, {name = 'C', width = 1.0, brand = 'BB'}]

productWidths = [(A: 1), (B: 4), (C: 2)]
brandWidths = [(BA: 5), (BB: 2)]

您可以使用
Dictionary(grouping:by:)
对项目进行分组,然后使用
mapValue
以所需的方式变换组

我认为有两种方法可以做到这一点。第一个更像您的方式,只是我使用了标准库函数来实现您对产品总数所做的操作

let items = [Item]()

let products = items.map { $0.product }

// This is your "productTotals"
let productTotalWidths = Dictionary(uniqueKeysWithValues:
    products.lazy.map { (product: Product) -> (key: Product, value: Double) in
        let totalWidth = product.width * product.count
        return (key: product, value: totalWidth)
    }
)

let productTotalWidthsBrand = Dictionary(grouping: productTotalWidths, by: { $0.key.brand })
    .mapValues { (pairs: [(key: Product, value: Double)]) -> Double in

        return pairs
            .lazy             // don't allocate intermediate array
            .map { $0.value } // pull out the totalWidths calculates earlier
            .reduce(0, +)     // sum them
    }
但是,正如您所看到的,第二步变得更难了,因为您需要重新组合字典(从按
产品
分组,到按
品牌
分组),这涉及到扁平化内部组(按
产品
分组)

这可以通过先按品牌分组,然后再进行其他操作来简化:

let items = [Item]()

let products = items.map { $0.product }

let productsByBrand = Dictionary(grouping: products, by: { $0.brand })


let productTotalWidthsByBrand = productsByBrand.mapValues { products in
        return products
            .lazy                        // don't allocate an intermediate array 
            .map { $0.width * $0.count } // calc total width per product
            .reduce(0, +)                // sum them
    }

扩展@matt的建议-我不知道你可以设定一个默认值,我忘记了同一个产品可能会出现多次

let productSpace = items.reduce(into: [Product:Double]()) { result, item in

   if let product = item.product {
                result[product, default: 0.0] += product.width * item.count
                }
            }

let brandSpace = productsSpace.reduce(into: [Brand:Double]()) { result, productSpace in
            if let brand = productSpace.key.brand {
                result[brand, default: 0.0] += productSpace.value
            }
        }

你能给我们一个完整的、可编译的例子和一些样本数据吗?使用
reduce(into:)
形成一个直方图。@matt更多细节或例子?@Alexander-Monica-如果我能做到这一点,我就不会问
items=[{ix=1,product=a,count=1},
不是有效的Swift。谢谢,不太清楚,因为$0.count实际上是该商品的一个属性。因此,按品牌分组的产品会丢失该商品,因此您无法进行计算。我认为@matts建议可能更简单-请参阅我的答案。
$0.count实际上是该商品的一个属性
,这正是我要求的原因一个可比较的例子。我不是要一个可比较的解决方案,而是一个让我们开始的测试夹具,所有正确的数据类型<代码>项目<代码>,<代码>产品<代码>,<代码>品牌<代码>,等等,还有一些示例数据和一些预期结果。如果没有这些,我们就只能玩评论乒乓球,猜测你不清楚的cri泰里亚。