【问题标题】:Clubbing object array俱乐部对象数组
【发布时间】:2019-04-19 13:54:53
【问题描述】:

是否有任何有效的方法来组合对象数组?我有一个模型[sales],它有saleAmount, soldBy。不同的客户可能会出售多种商品。所以我想要的是,如果物品由 ABC 出售,那么我想将 ABC 出售的 saleAmount 相加。下面给出一个例子。

class Sale  {

    var soldBy : String = "" 
    var saleAmount : Double = 0.00
}
var sales : [sale] = [sale]()

sales array contains:
[
["ABC", 1200.34],
["ABC", 999.34],
["ABC", 3499.99],
["DEF", 333.32],
["DEF", 778.12]
]

Expected output :
[["ABC", 5699.67],
["DEF" , 1111.44]]

【问题讨论】:

  • sale 是一个结构吗?如果是这样,请在您的问题中提供其声明
  • 销售是一类。我已经更新了我的问题

标签: ios arrays swift sorting generics


【解决方案1】:

拥有:

struct Sales {
    let name: String
    let amount: Float

    init(name: String, amount: Float) {
        self.name = name
        self.amount = amount
    }
}

我会补充:

extension Sales {
    init(withSales initialSales: Sales, otherSale: Sales) {
        self.init(name: initialSales.name, amount: initialSales.amount + otherSale.amount)
    }
}

我会用reduce(into:_:):

let sales: [Sales] = [Sales(name: "ABC", amount: 1200.34),
                      Sales(name: "ABC", amount: 999.34),
                      Sales(name: "ABC", amount: 3499.99),
                      Sales(name: "DEF", amount: 333.32),
                      Sales(name: "DEF", amount: 778.12)]

let reducedSale = sales.reduce(into: [Sales]()) { (currentResult, current) in
    if let existingSalesIndex = currentResult.firstIndex(where: { $0.name == current.name }) {
        let existingSale = currentResult[existingSalesIndex]
        currentResult[existingSalesIndex] = Sales(withSales: existingSale, otherSale: current)

    } else {
        currentResult.append(current)
    }
}

print("reducedSales: \(reducedSales: [AppName.Sales(name: "ABC", amount: 5699.67), AppName.Sales(name: "DEF", amount: 1111.44)])

由于你使用了一个类,你可以避免方便的初始化,而只需添加数量。

【讨论】:

  • 谢谢。我使用了上面的代码,如果让 existingSalesIndex = currentResult.firstIndex(where: { $0.name == current.name }) --> Value of type '[Sales]' has no member 'firstIndex'
  • 我猜你不使用 Swift 4.2?你必须重写它。做得不好(因为它不会在第一次遇到时停止,它可能是currentResult.filter({ $0.name == current.name }).first
  • 不。我用4.1。现在我在 let existingSale = currentResult[existingSalesIndex] 中得到“无法使用 'Sales' 类型的索引来下标 '[Sales]' 类型的值”
  • 有什么理由不想使用 Swift 4.2?否则你必须重写index(where:)。类似 `let existingIndex = NSNotFound;对于 anIndex,currentResults 中的 aSale { if aSale.name == current.name { index = anIndex;中断 } } if existingIndex != NSNotFound { currentResult.append(current) } else { let existingSale = currentResult[existingSalesIndex]; currentResult[existingSalesIndex] = Sales(withSales: existingSale, otherSale: current)}
  • 见 Martin R 的回答。他将输出映射到字典,这应该很快。与 Danyal Raza 的回答相同。
【解决方案2】:

销售类:

class Sale{
        var soldBy:String
        var amount:Double

        init(soldBy:String, amount:Double) {
            self.soldBy = soldBy
            self.amount = amount
        }
}

计算输出:

let output = sales.reduce([String:Double]()) { (result, sale) -> [String:Double] in
        var result = result
        result[sale.soldBy, default: 0.0] += sale.amount
        return result
}

参考:https://developer.apple.com/documentation/swift/dictionary/2925471-reduce

【讨论】:

    【解决方案3】:

    您可以从销售中创建一系列键/值对,并且 使用Dictionary(_:uniquingKeysWith:) 用唯一键和总和创建一个字典 对应值:

    struct Sale  {
        let soldBy: String
        let saleAmount: Double
    }
    
    let sales = [
        Sale(soldBy: "ABC", saleAmount: 1200.34),
        Sale(soldBy: "ABC", saleAmount: 999.34),
        Sale(soldBy: "ABC", saleAmount: 3499.99),
        Sale(soldBy: "DEF", saleAmount: 333.32),
        Sale(soldBy: "DEF", saleAmount: 778.12),
    ]
    
    let sums = Dictionary(sales.map { ($0.soldBy, $0.saleAmount) },
                          uniquingKeysWith: { $0 + $1 })
    
    print(sums)
    // ["ABC": 5699.67, "DEF": 1111.44]
    

    然后你可以从字典中创建一个销售数组:

    let sumSales = sums.map { Sale(soldBy: $0.key, saleAmount: $0.value) }
    
    print(sumSales)
    // [Sale(soldBy: "ABC", saleAmount: 5699.67), Sale(soldBy: "DEF", saleAmount: 1111.44)]
    

    出于演示目的,我假设Sale 是一个结构。

    【讨论】:

    【解决方案4】:

    你可以使用Dictionary(grouping:by:):

    let groupedSales: [Sale] = Dictionary(grouping: sales) { $0.soldBy }
        .lazy
        .map { element in
            let sum = element.value.lazy.map { $0.saleAmount }.reduce(0,+)
            //Or as suggested by Mr Martin: let sum = element.value.reduce(0, { $0 + $1.saleAmount })
            return Sale(soldBy: element.key, saleAmount: sum)
        }
    

    现在你可以打印结果了:

    for s in groupedSales {
        print(s.soldBy, s.saleAmount)
    }
    //ABC 5699.67
    //DEF 1111.44
    

    为方便起见,我已将此初始化程序添加到 Sale 类中:

    class Sale  {
        var soldBy : String = ""
        var saleAmount : Double = 0.00
    
        init(soldBy: String, saleAmount: Double) {
            self.soldBy = soldBy
            self.saleAmount = saleAmount
        }
    }
    

    【讨论】:

    • 或者,element.value.reduce(0, { $0 + $1.saleAmount }) 而不是惰性和映射。
    • @MartinR 我喜欢??
    【解决方案5】:

    从@DaniyalRaza 的回答开始,做一些清理工作:

    class Sale: CustomStringConvertible {
        var soldBy:String
        var amount:Double
    
        init(soldBy:String, amount:Double) {
            self.soldBy = soldBy
            self.amount = amount
        }
    
        //This lets us use string interpolation to display a `Sale` object
        var description: String {
            return "Sale(soldBy:\"\(soldBy)\",amount:\(amount)"
        }
    }
    
    let sales: [Sale] = [Sale(soldBy: "ABC", amount: 1200.34),
                          Sale(soldBy: "ABC", amount: 999.34),
                          Sale(soldBy: "ABC", amount: 3499.99),
                          Sale(soldBy: "DEF", amount: 333.32),
                          Sale(soldBy: "DEF", amount: 778.12)]
    
    
    let output: [Sale] = sales.reduce([String:Double]()) { (result, sale) -> [String:Double] in
        var result = result
        result[sale.soldBy, default: 0.0] += sale.amount
        return result
    }
        //Map the dictionary from the above back to an array
        .map { Sale(soldBy: $0.key, amount: $0.value) }
    
        //Sort the output back into alphabetical order by soldBy (if desired)
        //Note that sorting will take time, so only do this step if needed.
        .sorted { $0.soldBy < $1.soldBy }
    
    print(output)
    

    【讨论】:

    • 也许使用 reduce(into:) 来避免每次都创建一个可变副本?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-05
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    相关资源
    最近更新 更多