简体   繁体   中英

How can I get a cumulative average in a struct in Swift4?

I have the following struct.

struct Fruit {
    var name: String
    var stateCd: Int
    var amt: Int
    var cumulativeAvg: Int
}

var fruit = [
    Fruit(name: "apple", stateCd: 0, amt: 100, cumulativeAvg: 0),
    Fruit(name: "apple", stateCd: 0, amt: 200, cumulativeAvg: 0),
    Fruit(name: "apple", stateCd: 1, amt: 100, cumulativeAvg: 0),
    Fruit(name: "apple", stateCd: 0, amt: 300, cumulativeAvg: 0)
]

What I want is to change the value of the cumulativeAvg column to the cumulative average if stateCd is zero. If stateCd is 1, the previous average is taken without accumulating sum.

The changed values ​​are expected to be as follows.

Fruit(name: "apple", stateCd: 0, amt: 100, cumulativeAvg: 100),
Fruit(name: "apple", stateCd: 0, amt: 200, cumulativeAvg: 150),
Fruit(name: "apple", stateCd: 1, amt: 100, cumulativeAvg: 150),
Fruit(name: "apple", stateCd: 0, amt: 300, cumulativeAvg: 200)

A simple for loop can do so

var sum = 0
var count = 0
for i in 0..<fruit.count
{
    if(fruit[i].stateCd == 0)
    {
        count += 1
        sum += fruit[i].amt
        fruit[i].cumulativeAvg = sum/count
    }
    else if(fruit[i].stateCd == 1)
    {
        fruit[i].cumulativeAvg = sum/count
    }
}

This would be a better and cleaner approach to your problem.

struct Fruit {
    var name: String
    var stateCd: Int
    var amt: Double
    var cumulativeAvg: Double
}

Create another structure to store the count and average for a particular fruit.

struct FruitStats {
    var count: Double
    var average: Double
}

Maintain a dictionary which keeps track of the count and average for each fruit.

var fruitStats: [String: FruitStats] = [:]

var fruits = [
    Fruit(name: "apple", stateCd: 0, amt: 100, cumulativeAvg: 0),
    Fruit(name: "apple", stateCd: 0, amt: 200, cumulativeAvg: 0),
    Fruit(name: "apple", stateCd: 1, amt: 100, cumulativeAvg: 0),
    Fruit(name: "apple", stateCd: 0, amt: 300, cumulativeAvg: 0),
    Fruit(name: "orange", stateCd: 0, amt: 100, cumulativeAvg: 0),
    Fruit(name: "orange", stateCd: 1, amt: 100, cumulativeAvg: 0),
    Fruit(name: "orange", stateCd: 0, amt: 400, cumulativeAvg: 0)
]

let newFruits = fruits.map { (fruit) -> Fruit in
    var newFruit = fruit
    var fruitStat = fruitStats[fruit.name, default: FruitStats(count: 0, average: 0)]
    if fruit.stateCd == 0 {
        fruitStat.average *= fruitStat.count
        fruitStat.count += 1
        fruitStat.average = (fruitStat.average + fruit.amt)/fruitStat.count
    }
    newFruit.cumulativeAvg = fruitStat.average
    fruitStats[fruit.name] = fruitStat
    return newFruit
}

for fruit in newFruits {
    print(fruit.name, "\t", fruit.stateCd, fruit.amt, fruit.cumulativeAvg)
}
 apple 0 100.0 100.0 apple 0 200.0 150.0 apple 1 100.0 150.0 apple 0 300.0 200.0 orange 0 100.0 100.0 orange 1 100.0 100.0 orange 0 400.0 250.0 
fruit[0].cumulativeAvg = fruit[0].amt
for (i, f) in zip(1..., fruit.dropFirst()) {
    if f.stateCd == 1 {
        fruit[i].cumulativeAvg = fruit[i-1].cumulativeAvg
    } else {
        fruit[i].cumulativeAvg = (fruit[i-1].cumulativeAvg * i + fruit[i].amt) / (i+1)
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM