📌

割り勘計算 アルゴリズムの作成 in Swift

2022/07/18に公開

今回作るアルゴリズム

input Data
1. A が   A,C,D     3人分 1200円払った
3. B が   A,B,C,D   4人分 2400円払った
4. C が   A,B,C     3人分 3000円払った

のようなデータを入れると

output Data
1. D から   C に  1000円渡してください
2. A から   B に  800円渡してください

という形で計算できるコードを書いていこうと思います。

作成の主な流れ

  • input Dataをうまく扱えるようにする!
  • output Dataの形も決定する
  • アルゴリズム作成
    • なぜ頭で考えたらわかるのか?
    • 言語化 + 紙などに書いて実際に自分がどう計算しているのか?理解する

アルゴリズムの計算流れ

  1. 誰が何円損得している状態なのか?をinput Dataから計算する
  2. 損得同じなのであればそこで金銭取引を決定
  3. 同じ金額がなさそうであれば損得金額が大きい順に金銭取引を進める
  4. 最後に取引金額、人を出力する

実際の計算

誰が何円損得している状態なのか?をinput Dataから計算する

var outVolvesData: Dictionary<String, Int> = [:]
    
for i in memberName{
	outVolvesData[i] = 0
}

for data in history {
	var amount: Int = data.amount
	var payer: String = data.payer
	var involves: [String] = data.involves
	let payNum = Int(amount/involves.count)

for member in involves {
    if payer  == member{
	outVolvesData[member]! -= payNum*(involves.count-1)
	continue
    }
    outVolvesData[member]! += payNum
}


損得同じなのであればそこで金銭取引を決定

未実装

同じ金額がなさそうであれば損得金額が大きい順に金銭取引を進める

var sortOutVolves = outVolvesData.sorted(by: { $0.value > $1.value })
var pulsOutVolvesData: Dictionary<String, Int> = [:]
var mainsOutVolvesData: Dictionary<String, Int> = [:]
var ans_Ay:[PayersDecision] = []

for data in sortOutVolves{
    if data.value >= 0{
        pulsOutVolvesData[data.key] = data.value
    }else{
        mainsOutVolvesData[data.key] = data.value
    }
}

var pulsOutVolvesDataBeta:[[Any]] = []

for i in pulsOutVolvesData.sorted(by: { $0.value > $1.value }){
    pulsOutVolvesDataBeta.append([i.key, i.value])
}

var mainsOutVolvesDataBeta:[[Any]] = []

for i in mainsOutVolvesData.sorted(by: { $0.value < $1.value }){
    mainsOutVolvesDataBeta.append([i.key, i.value])
}

pulsOutVolvesDataBeta.sort{$0[1] as! Int > $1[1] as! Int}
mainsOutVolvesDataBeta.sort{$0[1] as! Int > $1[1] as! Int}
mainsOutVolvesDataBeta.reverse()

for mainsOutVolve in mainsOutVolvesDataBeta{
    var value = mainsOutVolve[1] as! Int
    pulsOutVolvesDataBeta.sort{$0[1] as! Int > $1[1] as! Int}
    for (num,plusOutVole) in pulsOutVolvesDataBeta.enumerated(){
        let watasimasita:Int = plusOutVole[1] as! Int + value
        if watasimasita >= 0 {
	    pulsOutVolvesDataBeta[num][1] = watasimasita
	    ans_Ay.append(PayersDecision(outVolves: abs(value) ,payer: plusOutVole[0] as! String,target:mainsOutVolve[0] as! String))
	    value = 0
	    break
        }else{
	    value = watasimasita
	    pulsOutVolvesDataBeta[num][1] = 0
	    ans_Ay.append(PayersDecision(outVolves: plusOutVole[1] as! Int ,payer: plusOutVole[0] as! String,target:mainsOutVolve[0] as! String))
	    continue
        }
    }
}

最後に取引金額、人を出力する

for i in ans_Ay{
    print("決定だよ〜〜")
    D から   C に  1000円渡してください
    print("\(i.payer!)から\(i.target!)\(i.outVolves!)円渡してください")
}

最後に作成した関数

input output  など使用しやすくした型
class PayHis: NSObject{
    var amount: Int!
    var payer: String!
    var involves: [String]!
    
    init(amount: Int,payer: String,involves: [String]) {
        self.amount = amount
        self.payer = payer
        self.involves = involves
    }
}
class PayersDecision: NSObject{
    var payer: String!
    var target: String!
    var outVolves: Int!
    
    init(outVolves: Int,payer: String,target:String) {
        self.outVolves = outVolves
        self.payer = payer
        self.target = target
    }
}
実装関数

func calclateGroupPay(history: [PayHis],memberName:[String]) {
    
    var outVolvesData: Dictionary<String, Int> = [:]
    
    for i in memberName{
        outVolvesData[i] = 0
    }
    
    for data in history {
        var amount: Int = data.amount
        var payer: String = data.payer
        var involves: [String] = data.involves
        let payNum = Int(amount/involves.count)
        
        for member in involves {
            if payer  == member{
                outVolvesData[member]! -= payNum*(involves.count-1)
                continue
            }
            outVolvesData[member]! += payNum
        }
    }
    
    var sortOutVolves = outVolvesData.sorted(by: { $0.value > $1.value })
    var pulsOutVolvesData: Dictionary<String, Int> = [:]
    var mainsOutVolvesData: Dictionary<String, Int> = [:]
    var ans_Ay:[PayersDecision] = []
    
    for data in sortOutVolves{
        if data.value >= 0{
            pulsOutVolvesData[data.key] = data.value
        }else{
            mainsOutVolvesData[data.key] = data.value
        }
    }
    
    var pulsOutVolvesDataBeta:[[Any]] = []
    
    for i in pulsOutVolvesData.sorted(by: { $0.value > $1.value }){
        pulsOutVolvesDataBeta.append([i.key, i.value])
    }
    
    var mainsOutVolvesDataBeta:[[Any]] = []
    
    for i in mainsOutVolvesData.sorted(by: { $0.value < $1.value }){
        mainsOutVolvesDataBeta.append([i.key, i.value])
    }
    
    pulsOutVolvesDataBeta.sort{$0[1] as! Int > $1[1] as! Int}
    mainsOutVolvesDataBeta.sort{$0[1] as! Int > $1[1] as! Int}
    mainsOutVolvesDataBeta.reverse()
    
    for mainsOutVolve in mainsOutVolvesDataBeta{
        var value = mainsOutVolve[1] as! Int
        pulsOutVolvesDataBeta.sort{$0[1] as! Int > $1[1] as! Int}
        for (num,plusOutVole) in pulsOutVolvesDataBeta.enumerated(){
            let watasimasita:Int = plusOutVole[1] as! Int + value
            if watasimasita >= 0 {
                pulsOutVolvesDataBeta[num][1] = watasimasita
                ans_Ay.append(PayersDecision(outVolves: abs(value) ,payer: plusOutVole[0] as! String,target:mainsOutVolve[0] as! String))
                value = 0
                break
            }else{
                value = watasimasita
                pulsOutVolvesDataBeta[num][1] = 0
                ans_Ay.append(PayersDecision(outVolves: plusOutVole[1] as! Int ,payer: plusOutVole[0] as! String,target:mainsOutVolve[0] as! String))
                continue
            }
        }
    }
    
    
    for i in ans_Ay{
        print("決定だよ〜〜")
        print("\(i.payer!)から\(i.target!)\(i.outVolves!)円渡してください")
    }
}

Discussion