过滤数组并将元素添加到一起

问题描述 投票:1回答:5

我读了一个我创建的随机文本文件

hard        toffee        10
hard        toffee        20
...
chewy       gum           40
soft        marshmallow   20
hard        toffee        30   
soft        marshmallow   40

我创建了一系列糖果/糖果对象并将其存储如下:

var candyArray = [
Candy(consistency: "hard", type: "toffee", cost: 10),
...
Candy(consistency: "soft", type: "marshmellow", cost: 40)]

可以通过其属性访问每个对象:

print(\(candyArray[0].type))
// prints toffeee

我想迭代数组,如果一致性很难,我想+ =用于存储硬糖成本总和的变量的成本。我想对其他一致性做同样的事情,然后将它们进行比较,看看总结时哪个成本最高。任何帮助都将非常感激。这是我到目前为止所拥有的:

struct Candy {
    var consistency: String
    var type: String
    var cost: Double

    init(consistency: String, type: String, cost: Double) {
        self.consistency = consistency
        self.type = type
        self.cost = cost
    }

}

var candyArray = [
    Candy(consistency: "hard", type: "toffee", cost: 40),
    Candy(consistency: "hard", type: "toffee", cost: 5),
    Candy(consistency: "hard", type: "toffee", cost: 5),
    Candy(consistency: "soft", type: "marshmallow", cost: 30),
    Candy(consistency: "soft", type: "marshmallow", cost: 35),
    Candy(consistency: "chewy", type: "gum", cost: 35)

]

print("\(candyArray[0].type)")

var x = 0
var largestValue = 0.0
var tempValue = 0.0

var currentConsistency = candyArray[x].consistency
var mostExpensiveConsistency = ""


while (x < candyArray.count){
    if (currentConsistency == candyArray[x].consistency) {
        tempValue += candyArray[x].cost
    } else if (currentConsistency != candyArray[x].consistency) {
        tempValue = 0
        currentConsistency = candyArray[x].consistency
    }

    if (tempValue > largestValue) {
        largestValue = tempValue
        mostExpensiveConsistency = currentConsistency
    }
    x+=1
}

print(" largest value: \(largestValue) and most expensive consistency: \(mostExpensiveConsistency)")

如果没有像我上面提到的上述文本文件那样排序一致性类型,则代码不起作用。我正在考虑创建一个二维数组或字典,并将一致性存储为键,并将其作为每个一致性的值,以便如果再次出现一致性,我可以将它添加到先前存储在数组/字典中的总和。我希望我有道理。我只是想知道是否有更快的方法来做到这一点。

arrays swift
5个回答
3
投票

您可以使用Array.reduce(into:)创建一个Dictionary,其密钥是一致性,值是具有该一致性的糖果成本的总和。然后,您只需在max(by:)上调用Dictionary即可找到最昂贵的一致性类型。

let candiesByConsistency = candyArray.reduce(into: [String:Double](), { accumulatedResults, current in
    accumulatedResults[current.consistency, default: 0] += current.cost
})

let mostExpensiveConsistency = candiesByConsistency.max(by: { $0.value < $1.value })

使用给定示例数组的candiesByConsistency的值将是

[“软”:65,“硬”:50,“耐嚼”:35]

mostExpensiveConsistency将是

(键“软”,值65)`


3
投票

Swift 4的字典初始化程序可以为您完成大部分工作。

例如:

let costs   = Dictionary(candyArray.map{($0.consistency,$0.cost)}, uniquingKeysWith:+)
let highest = costs.max{$0.value < $1.value} // ("soft",65)
let hardCost = costs["hard"] // 50

1
投票
  1. 定义字典以保存成本摘要。
  2. 迭代一系列糖果并总结成本,按一致性分组。
  3. 将摘要减少为单个值,始终选择成本最高的货币对。

let candies = [
    Candy(consistency: "b", type: "b", cost: 1.5),
    Candy(consistency: "a", type: "b", cost: 1.0),
    Candy(consistency: "a", type: "b", cost: 2.0),
    Candy(consistency: "c", type: "b", cost: 3.0),
    Candy(consistency: "b", type: "b", cost: 1.0),
    Candy(consistency: "c", type: "b", cost: 2.0),
]

// 1
var costSummary = [String: Double]()

// 2
candies.forEach {
    costSummary[$0.consistency] = (costSummary[$0.consistency] ?? 0.0) + $0.cost
}

// 3
let mostExpensive = costSummary.reduce(("", 0.0)) { result, next in
    return result.1 > next.1 ? result : next
}

1
投票

这是一个很好的管道,可以帮助您实现目标

let maxCost = Dictionary(grouping: candyArray, by: { $0.consistency }) // group candies by consistency
    .map { ($0.key, $0.value.reduce(0) { $0 + $1.cost }) } // compute the total cost for each consistency
    .sorted { $0.1 > $1.1 } // sort descending by price
    .first // take the first result

结果是可选的,这将指示您尝试处理空的糖果阵列(不太可能但可能的情况),因此您也可以处理那个。

顺便说一句,我不禁注意到你经常使用var,你可能想把所有那些var转换为只读的(也就是let)以获得更好的可预测性和更好的性能(如果编译器知道变量是一个变量,它就可以进行优化不变)。以下结构声明与您的相同(编译器免费提供的成员初始化程序):

struct Candy {
    let consistency: String
    let type: String
    let cost: Double
}

1
投票

Swift在集合上提供了一些很好的函数来简化这些类型的任务:mapfilterreduce

例如,您可以通过以下方式获得硬糖的总成本:

let hardCost = candyArray.filter{ $0.consistency == "hard" }.map{ $0.cost }.reduce(0, +)

这样做如下:

filter:返回一个只包含与指定条件匹配的项的数组(consistency == "hard"

map:返回filter结果中仅有成本的数组

reduce:通过对输入数组的所有元素执行操作(在本例中为+)来聚合单个结果

您可以为每种类型的一致性执行相同的过程,或者编写一个扩展方法,jut将获取所需的一致性名称,例如:

extension Array where Element == Candy {
    func costOf(consistency: String) {
        candyArray.filter{ $0.consistency == consistency }.map{ $0.cost }.reduce(0, +)
    }
}

然后像这样使用它来获得每个一致性的值:

let hardCost = candyArray.costOf(consistency: "hard")
let softCost = candyArray.costOf(consistency: "soft")
let chewyCost = candyArray.costOf(consistency: "chewy")
© www.soinside.com 2019 - 2024. All rights reserved.