Change value of variable by reference - swift

Hi I have 4 variables and I want to refer to one of them depending on some conditions, my current code looks as follows:
switch color {
case .Azul:
botonACambiar.tintColor = colores.salidaAzul
if backTees == true {
if option == 1{self.colorHcpBackTees1 = .Azul} else{self.colorHcpBackTees2 = .Azul}
} else {
if option == 1{self.colorHcpFrontTees1 = .Azul} else{self.colorHcpFrontTees2 = .Azul}
}
...
...
case . Cafe:
botonACambiar.tintColor = colores.salidaMarron
if backTees == true {
if option == 1{self.colorHcpBackTees1 = .Cafe} else{self.colorHcpBackTees2 = .Cafe}
} else {
if option == 1{self.colorHcpFrontTees1 = .Cafe} else{self.colorHcpFrontTees2 = .Cafe}
}
}
I have around 8 options, and as you can see it gets kind of messy.
So far I only have 4 different variables that i might manipulate:
Option 1 & 2 for FrontTees & option 1 & 2 for BackTees, but in the future the app might support more options and more colors for front and back tees.
This 4 values are saved in the app and because of this I need to keep track of them individually, thus I have the four variables:
var colorHcpBackTees1: ColoresDeSalidas = .Negra
var colorHcpBackTees2: ColoresDeSalidas = .Blanca
var colorHcpFrontTees1: ColoresDeSalidas = .Roja
var colorHcpFrontTees2: ColoresDeSalidas = .Blanca
Each with their default values, it would be nice to have a way of initializing a reference variable in such a way that I could do something like:
var choice: ColoresDeSalidas{
if backTees && option == 1 { return self.colorHcpBackTees1}
if backTees && option == 2 { return self.colorHcpBackTees2}
if !backTees && option == 1 { return self.colorHcpFrontTees1}
if !backTees && option == 2 { return self.colorHcpFrontTees2}
}
And simply use the variable choice to manipulate the value of the right variable

You can accomplish this using a ReferenceWritableKeyPath.
What is a ReferenceWritableKeyPath?
Think of it as a precise description of a property in a class or struct. A real world example would be The Empire State Building instead of the address which would be 20 W 34th St, New York, NY 10001. You could tell either one to a cab driver and she could take you there.
A ReferenceWritableKeyPath is a generic type. You need to specify the class or struct name and the type of the variable you will be accessing. So your choice variable would be a ReferenceWritableKeyPath<YourClass,ColoresDeSalidas>.
Here is a standalone example:
enum ColoresDeSalidas : String {
case Negra
case Blanca
case Roja
case Azul
case Verde
}
class Foo {
var backTees = false
var option = 1
var colorHcpBackTees1: ColoresDeSalidas = .Negra
var colorHcpBackTees2: ColoresDeSalidas = .Blanca
var colorHcpFrontTees1: ColoresDeSalidas = .Roja
var colorHcpFrontTees2: ColoresDeSalidas = .Blanca
var choice: ReferenceWritableKeyPath<Foo,ColoresDeSalidas> {
if backTees && option == 1 { return \.colorHcpBackTees1 }
if backTees && option == 2 { return \.colorHcpBackTees2 }
if !backTees && option == 1 { return \.colorHcpFrontTees1 }
if !backTees && option == 2 { return \.colorHcpFrontTees2 }
fatalError("We were supposed to return a keyPath for choice")
}
func test() {
backTees = true
option = 2
print("Before: \(self.colorHcpBackTees2)")
// Now update the correct property using the choice KeyPath
self[keyPath: choice] = .Azul
print("After: \(self.colorHcpBackTees2)")
backTees = false
option = 1
// Assign it to another variable, just to show you can
let choiceFront1 = choice
option = 2
// choiceFront1 still refers to !backTees and option 1
// even though option and choice have changed
print("colorHcpFrontTees1 = \(self[keyPath: choiceFront1])")
colorHcpFrontTees1 = .Verde
print("colorHcpFrontTees1 = \(self[keyPath: choiceFront1])")
}
}
Run the test:
Foo().test()
Output:
Before: Blanca
After: Azul
colorHcpFrontTees1 = Roja
colorHcpFrontTees1 = Verde

To clean the code you could wrap the logic for initialising the properties within the enum itself.
extension ColoresDeSalidas {
init?(isBackTee: Bool, option: Int) {
switch (isBackTee, option) {
case (true, 1): self = .colorHcpBackTees1
case (true, 2(: self = .colorHcpBackTees2
case (false, 1): self = .colorHcpFrontTees1
case (false, 2): self = .colorHcpFrontTees2
default: return nil //or assign a default and make non-failable
}
And then you can initialise / update with:
let myVar = ColoresDeSalidas(isBackTee: true, option: 1)

Related

What should change for the this code to correctly identify balanced Trees?

I'm doing this leetcode problem.
I already have done another implementation that uses a height function. That works.
I have this other implementation. Visually when I look at the problem I get why it won't work. But I can't find words to write it down for myself as to why it doesn't work.
It fails on its 214th test for [1, 2, 2, 3, 3, null, null, 4, 4]
class Solution {
// for every node I have to go 2 levels down.
// if left existed, then see if right exists, and traverse down
// if left existed and had children but right didn't exist then return `false`
// or if right existed and had children but left didn't exist then return `false`
func isBalanced(_ root: TreeNode?) -> Bool {
if let left = root?.left {
if let right = root?.right {
return isBalanced(left) && isBalanced(right)
} else if left.left != nil || left.right != nil {
return false
}
} else if let right = root?.right {
if root?.left == nil {
if right.left != nil || right.right != nil {
return false
}
}
}
return true
}
}
To be clear I'm not looking for alternate solutions. I'm only trying to understand why the current implementation doesn't work.
Take for instance this tree:
8
/ \
4 9
/ \
2 6
/ \ / \
1 3 5 7
Starting at the root, the execution of this code will enter the inner if block:
if let left = root?.left {
if let right = root?.right {
return isBalanced(left) && isBalanced(right)
...and the two recursive calls will return true, because indeed those subtrees are balanced on their own, and so this tree will be identified as balanced. Yet it is clear this is not the case.
You will really need to retrieve the heights of the subtrees and compare them.
This isn't an alternate solutions, I just removed unnecessary check...
class TreeNode {
constructor(left, right) {
this.left = left
this.right = right
}
isEndNode() { return this.left == null && this.right == null; }
isBalanced() {
if (this.isEndNode()) return true;
if (this.left && this.right)
return this.left.isBalanced() && this.right.isBalanced();
return false
}
}
let node = (left, right) => new TreeNode(left, right);
let root1 = node(node(node(), node()), node(node(), node()))
let root2 = node(node(node(), node()), node(node(), null))
let root3 = node(node(null, node()), node(node(), node()))
console.log(root1.isBalanced()) // true
console.log(root2.isBalanced()) // false
console.log(root3.isBalanced()) // false

Setting an immutable variable with conditional logic in Swift

I have a super simple question on the best way (i.e. style) to do this correctly in Swift.
if a > b {
let x = 1
} else {
let x = 2
}
//then procede to use x
Obviously, this will not work, because the scope of x is only within each branch of the if. But what is the preferred way to go about this, if I want x to be immutable? So far, I have been doing this:
var x:Int
if a > b {
x = 1
} else {
x = 2
}
//then procede to use x
which works, but leaves x as mutable. The next choice is to use the ternary operator as in:
let x = a > b ? 1 : 2
This leaves x immutable but leaves a bit to be desired in terms of readability when the conditions and resulting values become complex. Also, using the ternary solution completely falls down with a more complex example:
if a > b {
let x = 1
} else if b > c {
let x = 2
} else {
let x = 3
}
}
//procede to use x
or this:
switch a {
case 1:
let x = 1
case 2:
let x = 2
default:
let x = 3
}
//procede to use x
Is their any way to promote the scope of a let outward one level, or some other way this type of situation is normally handled?
You can use let in your 2nd example:
let x:Int
if a > b {
x = 1
} else {
x = 2
}
As long as x is fully initialized in all paths, this works.
It works with the switch as well:
let a = 3
let x: Int
switch a {
case 1:
x = 1
case 2:
x = 2
default:
x = 3
}
you can also achieve it using class.
like this
class immutableVariable{
private var value: Any
init(newValue: Any = "") {
self.value = newValue
}
func changeValue(withNewValue newValue: Any){
self.value = newValue
}
func getValue() -> Any{
return value
}
}
and then call it like
let x = immutableVariable()
if a > b{
x.changeValue(withNewValue: 1)
}else{
x.changeValue(withNewValue: 2)
}
and access values using
print(x.getValue())

Swift on array.sort - Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions

I am downgrading Swift code from Xcode 8.3.1 to Xcode 7.3.1.
The Swift compiler of Xcode 7.3.1 raises
Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
while pointing on line zeroParameterAndPaths.sort {. The code was ok in Xcode 8.3.1.
What's wrong and how to fix it?
class NewConnectingSegmentZeroParameterAndPath {
let step : Int; // 0 = main, 1 = first outline, 2 = second outline
let parameter : CGFloat;
init(step: Int, parameter: CGFloat) {
self.step = step;
self.parameter = parameter;
}
}
var zeroParameterAndPaths : [NewConnectingSegmentZeroParameterAndPath] = [];
// ... some zeroParameterAndPaths .appendContentsOf calls
zeroParameterAndPaths.sort {
return $0.parameter < $1.parameter
|| ($0.parameter == $1.parameter
&& ($0.step == 1 || ($0.step == 0 && $1.step == 2))
)
};
You have two choices. One is simply to do what the error message suggests, i.e. pulling the complex bool apart into separate pieces:
zeroParameterAndPaths.sort {
let bless = ($0.parameter < $1.parameter)
let beq = ($0.parameter == $1.parameter)
let band = ($0.step == 0 && $1.step == 2)
let bor = ($0.step == 1 || band)
let beqandbor = (beq && bor)
return (bless || beqandbor)
};
The other is to provide an explicit in line giving the param types and result type:
zeroParameterAndPaths.sort {
(a:NewConnectingSegmentZeroParameterAndPath, b:NewConnectingSegmentZeroParameterAndPath) -> Bool in
return a.parameter < b.parameter
|| (a.parameter == b.parameter
&& (a.step == 1 || (a.step == 0 && b.step == 2))
)
};
You could also make your class a little bit more helpful and make it implement the condition. The compiler is much less likely to get confused in a function body than in a closure:
class NewConnectingSegmentZeroParameterAndPath {
let step : Int; // 0 = main, 1 = first outline, 2 = second outline
let parameter : CGFloat;
init(step: Int, parameter: CGFloat) {
self.step = step;
self.parameter = parameter;
}
func orderedBefore(_ other: NewConnectingSegmentZeroParameterAndPath) -> Bool
{
return parameter < other.parameter
|| parameter == other.parameter
&& (step == 1 || step == 0 && other.step == 2)
}
}
var zeroParameterAndPaths : [NewConnectingSegmentZeroParameterAndPath] = [];
// ... some zeroParameterAndPaths .appendContentsOf calls
zeroParameterAndPaths.sort { $0.orderedBefore($1) }
Apart from the issue of the type inference engine not being able to quickly resolve such complex bool expressions, such expressions are really hard to follow. I suggest you break it down into something simpler, like so:
zeroParameterAndPaths.sort {
if $0.parameter != $1.parameter { return $0.parameter < $1.parameter ]
if $0.step == 1 { return true }
if $0.step == 0 && $1.step == 2 { return true }
return false
};
There's my attempt at it. I'm not even sure if it's correct, the original expression is pretty hard to follow.

How to make changes to a variable inside an if statement

I'm trying to make changes to a var inside an if statement, for some reason I can not get it to change.
func checkIfFieldsEmpty()-> Bool{
var textfieldStatus:Bool!
var v = [
"name" : ""
]
for (key, value) in v {
if value == "" {
textfieldStatus = false
} else {
textfieldStatus = true
}
}
return textfieldStatus
}
That will always return false. If you want to check if the values are completely empty, then I think you want this.
for (key, value) in textfield {
if value == "" {
textfieldStatus = false
}else{
textfieldStatus = true
break
}
}
According to #fridgemagnet answer, the difference is you are calling a method which required a Dictionary parameter. But you are always setting a
var v = [ "name":""]
And you are checking the variable "v" value which should always return false and by default your "textfieldStatus" value is false. So there is no chance to change your "textfieldStatus" value. Please make sure what you exactly want.
You define v as empty, and then check if its empty. Try v = ["name": "peter"](but, it's not really what you want). When you declare var v = ..., you are clearing the previous values for v if it is defined earlier in the program.
This solution work well form me
func checkIfFieldsEmpty()-> Bool{
var v = [
"name":""
]
var textfieldStatus:Bool = true
var fielderrorCount:Int = 0
for (key, value) in v{
if value == ""{
fielderrorCount = 1
}
}
if fielderrorCount > 0{
textfieldStatus = false
}
return textfieldStatus
}

Changing an attribute in an object that belongs to RDD

I have the following code :
def generateStoriesnew(outputPath: String, groupedRDD:RDD[(String,Iterable[String])], isInChurnMode: Boolean, isInChurnPeriod: Boolean) {
val windowedRDD = groupedRDD.map(SOME CODE)
var windowedRDD2 = windowedRDD.filter(r => r != null).map(a=>a.churnPeriod(isInChurnPeriod,isInChurnMode))
val prettyStringRDD = windowedRDD2.map(r => {
r.toString
})
prettyStringRDD.saveAsTextFile(outputPath)
}
and here is the code for ChurnPriod function:
def churnPeriod( churnPeriod:Boolean, churnMode: Boolean): Unit = {
if (churnMode && rootEventType.equalsIgnoreCase("c")){
var churnCustStory: CustStoryN = null
var nonChurnCustStory: CustStoryN = null
var churnPeriodEventStory: mutable.MutableList[StoryEventN] = null
var NonChurnEventstory: mutable.MutableList[StoryEventN] = null
churnPeriodEventStory = new mutable.MutableList[StoryEventN]
NonChurnEventstory = new mutable.MutableList[StoryEventN]
var lastEventChurnPeriod = true
var currentEventStory = eventStory
var max = currentEventStory.length
println(max);
if (currentEventStory.size > 0) {
for (i <- 0 until currentEventStory.length) {
var currentEvent = currentEventStory(i)
if (currentEvent.timeSenseRootEvent < 90) {
churnPeriodEventStory.+=(currentEvent)
//lastEventChurnPeriod = true
}
else {
NonChurnEventstory.+=(currentEvent)
lastEventChurnPeriod = false
}
}
}
if (churnPeriod)
eventStory = churnPeriodEventStory
else
eventStory=null
}
}
but churn period function does not change eventstory which is a member of a custstory class. what am I missing here ?
class CustStoryN (val custId:String,
var rootEventType:String,
var rootEventTime:Long,
var eventStory:mutable.MutableList[StoryEventN])
my hypothesis is either:
1.map is not the right transformation for the function that I have
2.churnPeriod function never get called
3.I can not change eventstory which is a member of cust story class
Does anyone have any idea how I can troubleshoot this problem?
This would be trivial to determine by debugging. Just put a few breakpoints and you can see if the program stops inside the function, and what transformations do occur.
My guess would be that the problem is this line: if (currentEventStory.size > 0), thus, a list that starts at size 0 remains at size 0 forever. Another option is that churnPeriod is never true, thus, you compute a lot but never assign to the eventStory variable.
Your code does need a good cleanup ;-)