Filtering arrays and adding elements together

时间:2018-02-26 17:40:49

标签: arrays swift

I read in a random text file I've created

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

I create an array of sweets/candy objects and store it like this:

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

Each object can be accessed through its properties:

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

I'd like to iterate through the array and if the consistency is hard, I want to += the cost to a variable used to store the sum of cost for hard candy. I want to do the same with the other consistencies and then compare them to see which has the greatest cost when summed up. Any help at all would be greatly appreciated. Here's what I have so far:

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

The code doesn't work when the consistency type isn't ordered like in the above text file I mentioned. I was thinking of creating a 2d array or a dictionary and storing the consistency as a key and sum as a value for each consistency so that if the consistency appears again I can add it to the sum that was previously stored in an array/dictionary. I hope I made sense. I'm just wondering if there's a faster way of doing this.

4 个答案:

答案 0 :(得分: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)

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

例如,你可以通过写下来获得硬糖的总成本:

reduce

执行以下操作:

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, +)
    }
}

答案 2 :(得分:1)

  1. 定义字典以保存费用摘要。
  2. 迭代一系列糖果并总结成本,按一致性分组。
  3. 将摘要简化为单个值,始终选择成本最高的一对。
  4. 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
    }
    

答案 3 :(得分:1)

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

x = ActiveSupport::MessageEncryptor.new('12345678901234567890123456789012').encrypt_and_sign('foo')
=> "bXJmRUczdjVXRFdLTitUcmkvRnk1UT09LS0vb2ZYdDRybGdWbmNXMUI1VDNnQzVBPT0=--13232bbe31d966f7d1df3aaa6fcc1cdc9eea60a1"
ActiveSupport::MessageEncryptor.new('12345678901234567890123456789012').decrypt_and_verify(x)
=> "foo"

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

顺便说一句,我无法注意到您经常使用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转换为只读varlet为了更好的可预测性和更好的性能(编译器可以在知道变量是常量的情况下进行优化)。以下结构声明与您的相同(编译器免费提供的成员初始化程序):

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