-2

I am working in a Swift Playground and I am using multiple toggles to determine if an action in true or false. And from there, the specific combination of them will display a number assigned to each combination. Since I have 4 toggles, I decided to make 16 if else statements but it is really slowing down my playground. Is there a way to use less statements?

Toggle(isOn: $washingHandsToggle) {
                    Text("Washing Hands Regularly")
                }.padding(40)

                Toggle(isOn: $wearingMaskToggle) {
                    Text("Wearing a Protective Mask")
                }.padding(40)

                Toggle(isOn: $coverMouthToggle) {
                    Text("Cover your mouth and nose when coughing or sneezing")
                }.padding(40)

                Toggle(isOn: $quarantineToggle) {
                    Text("Quarantine")
                }.padding(40)


                if !washingHandsToggle && !wearingMaskToggle && !coverMouthToggle && !quarantineToggle {
                    self.r0 = 1.0
                }else if !washingHandsToggle && !wearingMaskToggle && coverMouthToggle && !quarantineToggle {
                    self.r0 = 2.0

                }else if washingHandsToggle && !wearingMaskToggle && !coverMouthToggle && !quarantineToggle {
                    self.r0 = 3.0

                }else if !washingHandsToggle && wearingMaskToggle && !coverMouthToggle && !quarantineToggle {
                    self.r0 = 4.0

                }else if washingHandsToggle && !wearingMaskToggle && coverMouthToggle && !quarantineToggle {
                    self.r0 = 5.0

                }else if !washingHandsToggle && wearingMaskToggle && coverMouthToggle && !quarantineToggle {
                    self.r0 = 6.0

                }else if washingHandsToggle && wearingMaskToggle && !coverMouthToggle && !quarantineToggle {
                    self.r0 = 7.0

                }else if washingHandsToggle && wearingMaskToggle && coverMouthToggle && !quarantineToggle {
                    self.r0 = 8.0

                }else if !washingHandsToggle && !wearingMaskToggle && !coverMouthToggle && quarantineToggle {
                    self.r0 = 9.0

                }else if !washingHandsToggle && !wearingMaskToggle && coverMouthToggle && quarantineToggle {
                    self.r0 = 10.0

                }else if washingHandsToggle && !wearingMaskToggle && !coverMouthToggle && quarantineToggle {
                    self.r0 = 11.0

                }else if !washingHandsToggle && wearingMaskToggle && !coverMouthToggle && quarantineToggle {
                    self.r0 = 12.0

                }else if washingHandsToggle && !wearingMaskToggle && coverMouthToggle && quarantineToggle {
                    self.r0 = 13.0

                }else if !washingHandsToggle && wearingMaskToggle && coverMouthToggle && quarantineToggle {
                    self.r0 = 14.0

                }else if washingHandsToggle && wearingMaskToggle && !coverMouthToggle && quarantineToggle {
                    self.r0 = 15.0

                }else {
                    self.r0 = 16.0
                }

EliasFiz
  • 35
  • 7
  • Firstly, I would say that would look better as a Switch statement. What does the r0 value do? Could you assign a value to each toggle such as 1,2,4,8 and total them up, which would give you a unique result for each combination? – rbaldwin May 10 '20 at 11:45
  • It looks like you want the lowest value to be when they’re not taking any precautions, and the highest value when they are being good . You have 4 bools, with 16 combinations. Check out swift’s bitwise stuff. Basically you wanna treat each bool as a bit, so 0000, up to 1111 and then your number is just the decimal conversion of that binary number. – Peter Parker May 10 '20 at 11:47
  • @PeterParker If want to use specific numbers (like 1.4, 0.7, 4.7) instead of 1-16 what should I do – EliasFiz May 10 '20 at 11:59

3 Answers3

3

I would convert the state of the 4 switches to 1/0 and then map these bits into a 4 bit number, giving a value from 0-15

let washingHands:Int = washingHandsToggle.isOn ? 1:0
let wearingMask:Int = wearingMaskToggle.isOn ? 1:0
let coverMouth:Int = coverMouthToggle.isOn ? 1:0
let quarantine:Int = quarantineToggle.isOn ? 1:0

let stateValue = washingHands <<3 
                 | wearingMask << 2 
                 | coverMouth << 1 
                 | quarantine
Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • Thanks a lot @Paulw11, but what if want to use specific numbers (like 1.4, 0.7, 4.7) instead of 0-15 what should I do – EliasFiz May 10 '20 at 12:02
  • Create an array with those float values and use the 0-16 as an index into that array – Paulw11 May 10 '20 at 12:10
  • I'm sorry but I don't really understand How I would be able to do that. I understand the array part but how can I gather the 0-15 digits? – EliasFiz May 10 '20 at 12:30
  • It combines the values, shifting left by 3, 2 or 1 place and ORs them together which gives you a value from 0 to 15 depending on which switches are on – Paulw11 May 10 '20 at 12:33
3

Looks to me like you could convert this to a simple math operation since you are only interested in a toggle when the value is true

let value = (coverMouthToggle ? 1.0 : 0.0) +
    (washingHandsToggle ? 2.0 : 0.0) +
    (wearingMaskToggle ? 4.0 : 0.0) +
    (quarantineToggle ? 8.0 : 0.0)

(Note, you might have to adjust the score for each since I am not sure I got them right)

Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
1

I thought it might be fun to see an implementation using Combine. This isn't SwiftUI code, but since SwiftUI uses Combine throughout, it shouldn't be that hard to adapt.

In this example, instead of hard-coding the weights for the four toggles, we keep those weights in an array, weights, and you can thus assign or modify them as you like. The toggles are UISwitch objects pointed to through an outlet collection, toggles.

import UIKit
import Combine
class ViewController: UIViewController {
    @IBOutlet var toggles: [UISwitch]!
    var publishers = [CurrentValueSubject<Bool, Never>]()
    var storage = [AnyCancellable]()
    let weights = [1.0, 0.7, 2.5, 1.3] // or whatever
    var sum = 0.0 {
        didSet { print(sum) }
    }
    @objc func routeToPublisher(_ toggle: UISwitch) {
        if let index = toggles.firstIndex(of: toggle) {
            publishers[index].send(toggle.isOn)
        }
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        toggles.forEach {
            $0.addTarget(self, action: #selector(routeToPublisher), for: .valueChanged)
            publishers.append(CurrentValueSubject($0.isOn))
        }
        publishers[0].combineLatest(publishers[1], publishers[2], publishers[3]) { [$0,$1,$2,$3] }
            .map {
                $0.enumerated().map { pair in
                    (pair.element ? 1.0 : 0.0) * self.weights[pair.offset]
                }.reduce(0.0) {$0 + $1}
            }
            .assign(to: \.sum, on: self)
            .store(in: &storage)
    }
}

Every time the user toggles a switch, the weighted sum for all "on" switches is recalculated and appears in self.sum, and you can do anything you like with it. In the example I'm just printing it, but obviously you could make it appear in the interface, publish-and-subscribe to it and use it in a further calculation, and so on.

matt
  • 515,959
  • 87
  • 875
  • 1,141