dinggu
dinggu

Reputation: 111

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)

Upvotes: 1

Views: 117

Answers (3)

Rakesha Shastri
Rakesha Shastri

Reputation: 11242

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

Upvotes: 1

BallpointBen
BallpointBen

Reputation: 13820

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

Upvotes: 0

Ricky Mo
Ricky Mo

Reputation: 7698

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
    }
}

Upvotes: 1

Related Questions