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



我在创建的随机文本文件中读取

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)")

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

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

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)'

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. 定义一个字典来保存成本摘要。
  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
}

这里有一个很好的管道,可以帮助你实现你的目标

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's) 以获得更好的可预测性和更好的性能(如果编译器知道变量是常量,它可以进行优化)。以下结构声明与您的结构声明相同(编译器免费提供的成员初始值设定项):

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

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")

最新更新