Shortening If/Else from if(x == y || x == z) to if(x == y || z) in swift - swift

I'm making an app where I have to put a lot of if/else statements. I know you can do as in the title in some other coding language, but I'm not sure if you can do it in Swift.
How do you shorten this:
if x == y || x == z {
//do something
}
To something like this:
if x == y || z {
//do something
}

Perhaps you could consider using an array and checking to see if x is in the array, like in the following example:
let (x, y, z) = (3, 8, 3)
if [y, z].contains(x) {
//True
}
If you're comparing objects (like UIImage), use containsObject instead of contains:
if [x, y, z].containsObject(y) {
//True
}

I conject that there is no sensible language (swift included), that distributes comparison == across logical or ||.
The way you've written it - x == y || x == z - is the most compact form.

Jack Greenhill's answer does indeed go into the right direction. However with more and more values, his method will get very inefficient, since it has to check every element of the array against equality, therefore complexity O(n).
A very underrated data structure, which can do this kind of operation in O(1) should be used instead: The Set. It uses hash values to check quickly whether a value is present or not. You can use it like this:
let x = 3
let values : Set = [1, 3, 6, 1, 7] // {6, 7, 3, 1}
if values.contains(x) {
// ...
}
This takes the same amount of time, whether values contains just one or 1000 elements. An array would be 1000 times slower.
Oftentimes the decision to use an array is made before even considering a set. If your elements don't have any order and can only occur once (which is actually more often the case than you'd think), you probably want a set. A set gives you useful methods, such as union, isSubset, interception and more, for free by just putting your elements in it. The only additional requirement for the element type is to conform to Hashable.

Perhaps this:
switch x {
case y, z : // do then
default : // do else
}

Related

Logic behind Two Number Sum Algorithm

Could someone explain to me the logic behind this hashMap algorithm? I'm getting confused about how the algorithm receives the total sum. I'm starting to learn about algorithms, so it's a little confusing for me. I made comments in my code to pinpoint each line code, but I'm not sure I'm grasping logic correctly. I'm just looking for an easier way to understand how the algorithm works to avoid confusing myself.
//**calculate Two Number Sum
func twoNumberSum(_ array: [Int], _ targetSum: Int) -> [Int] {
//1) initilize our Array to hold Integer Value: Boolean value to store value into hashTable
var numbersHashMap = [Int:Bool]()
//2) create placeHolder called number that iterates through our Array.
for number in array {
//3) variable = y - x
let match = targetSum - number
//4) ??
if let exists = numbersHashMap[match], exists {
//5) match = y / number = x
return [match, number] //
} else {
//6) Store number in HashTable and repeats
numbersHashMap[number] = true
}
}
return []
}
twoNumberSum([3,5,-4, 8, 11, 1, -1, -6], 10)
// x = Number
// y = Unknown *Solve for Y*
Sure, I can walk you through it. So we have a list of numbers, are we are trying to find two numbers that add together to make the specified target. To do this, for each number x, we check if (target - x) is in the list. If it is not, then we add x to the list. If it is, then we return x and (target - x).
Step 4 in your code is the part where we check if (target - x) is in the list. To see why this makes sense, let's walk through an example.
Say we have [2, 3, -1] and our target is 1. In this case, we first consider x = 2 and check our hashmap for (target - x) = (1 - 2) = -1. Since -1 is not in the hashmap, we add 2 to the hashmap. We then consider x = 3 and check for (1 - 3) = -2. Again, -2 is not in the hashmap, so we add it. Now we check x - -1. In this case, when we check (target - x) = (1 - (-1)) = 2, 2 is in the hashmap. Intuitively, we have already "seen" 2, and know that 2 and -1 can be added to get our value.
This is what provides the speed optimization over checking every two numbers in the list.

Set/sequence summation operator?

I have a set, S = { 1, 2, 3, 4, 5 }.
If I wanted to sum this in standard logic it's just ∑S (no MathJax on SO so I can't format this nicely).
What's the VDM equivalent? I don't see anything in the numerics/sets section of the language reference.
There isn't a standard library function to do this (though perhaps there should be). You would sum a set with a simple recursive function:
sum: set of nat +> nat
sum(s) ==
if s = {}
then 0
else let e in set s in
e + sum(s \ {e})
measure card s;
The "let" selects an arbitrary element from the set, and then add that to the sum of the remainder. The measure says that the recursion always deals with smaller sets.
This should work:
sum(S)
But you could find this very easily.

GEN_NO_GENERATABLE_NOTIF

I want to choose index from list, so the element[index] complies my condition.
MyList[index].num==0
I tried the code bellow:
gen DescIdx2Choose keeping {
it < MyList.size();
MyList[it].num==0;//I tried a few way of read_only
};
How can I do it without using all_indices?
Thanks
Since you generating DescIdx2Choose then MyList will be input to the problem.
Therefore,
If seeking for the first index (if exists) then using random generation isn't required. Use the procedural code "first_index" as user3467290 suggested which is much more efficient:
var fidx := MyList.first_index(.num == 0);
if ( fidx != UNDEF ) {
DescIdx2Choose = fidx;
} else {
// error handling
};
If there are multiple indices and it is required to choose a random one, the most efficient way would be using "all_indices" as Thorsten suggested:
gen DescIdx2Choose keeping {
it in read_only( MyList.all_indices(.num == 0) );
};
The reason is the random generator doesn't need to read all possible values of "MyList.num" only a shorter list of valid indices.
This should do it, but MyList must fulfill the condition otherwise you get a contradiction. Pseudo-method first_index() is not bi-directional which is what we need here.
gen DescIdx2Choose keeping {
MyList.first_index(.num == 0) == it;
};
Maybe i missed something in the question, but If you always want the index of the first element that its num == 0, then why use constraints? can assign DescIdx2Choose == MyList.first_index(.num == 0).
To ensure that there is at least one such element, can constrain MyList.has(.num == 0).
Do you have additional constraints on DescIdx2Choose ?

Better way to find sums in a grid in Swift

I have an app with a 6x7 grid that lets the user input values. After each value is obtained the app checks to find if any of the consecutive values create a sum of ten and executes further code (which I have working well for the 4 test cases I've written). So far I've been writing if statements similar to the below:
func findTens() {
if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue + rowOneColumnFourPlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue + rowOneColumnFourPlaceHolderValue + rowOneColumnFivePlaceHolderValue) == 10 {
//code to execute
}
That's not quite halfway through row one, and it will end up being a very large set of if statements (231 if I'm calculating correctly, since a single 7 column row would be 1,2-1,2,3-...-2,3-2,3,4-...-67 so 21 possibilities per row). I think there must be a more concise way of doing it but I've struggled to find something better.
I've thought about using an array of each of the rowXColumnYPlaceHolderValue variables similar to the below:
let rowOnePlaceHolderArray = [rowOneColumnOnePlaceHolderValue, rowOneColumnTwoPlaceHolderValue, rowOneColumnThreePlaceHolderValue, rowOneColumnFourPlaceHolderValue, rowOneColumnFivePlaceHolderValue, rowOneColumnSixPlaceHolderValue, rowOneColumnSevenPlaceHolderValue]
for row in rowOnePlaceHolderArray {
//compare each element of the array here, 126 comparisons
}
But I'm struggling to find a next step to that approach, in addition to the fact that those array elements then apparently because copies and not references to the original array anymore...
I've been lucky enough to find some fairly clever solutions to some of the other issues I've come across for the app, but this one has given me trouble for about a week now so I wanted to ask for help to see what ideas I might be missing. It's possible that there will not be another approach that is significantly better than the 231 if statement approach, which will be ok. Thank you in advance!
Here's an idea (off the top of my head; I have not bothered to optimize). I'll assume that your goal is:
Given an array of Int, find the first consecutive elements that sum to a given Int total.
Your use of "10" as a target total is just a special case of that.
So I'll look for consecutive elements that sum to a given total, and if I find them, I'll return their range within the original array. If I don't find any, I'll return nil.
Here we go:
extension Array where Element == Int {
func rangeOfSum(_ sum: Int) -> Range<Int>? {
newstart:
for start in 0..<count-1 {
let slice = dropFirst(start)
for n in 2...slice.count {
let total = slice.prefix(n).reduce(0,+)
if total == sum {
return start..<(start+n)
}
if total > sum {
continue newstart
}
if n == slice.count && total < sum {
return nil
}
}
}
return nil
}
}
Examples:
[1, 8, 6, 2, 8, 4].rangeOfSum(10) // 3..<5, i.e. 2,8
[1, 8, 1, 2, 8, 4].rangeOfSum(10) // 0..<3, i.e. 1,8,1
[1, 8, 3, 2, 9, 4].rangeOfSum(10) // nil
Okay, so now that we've got that, extracting each possible row or column from the grid (or whatever the purpose of the game is) is left as an exercise for the reader. 🙂

How do you assign a slice of numbers to an array in swift

x is an object that holds an array called point.
x implements the subscript operator so you can do things, like x[i] to get the array's ith element (of type T, which is usually an Int or Double).
This is what I want to do:
x[0...2] = [0...2]
But I get an error that says ClosedInterval<T> is not convertible to Int/Double.
Edit1:
Here is my object x:
let x = Point<Double>(dimensions:3)
For kicks and giggles: define x as [1.0,2.0,0.0]
I can get the first n elements via x[0...2].
What I want to know is how to update x[0...2] to hold [0.0, 0.0.0.0] in one fell swoop. Intuitively, I would want to do x[0...2] = [0...2]. This does not work as can be seen in the answers. I want to update x without iteration (on my end) and by hiding the fact that x is not an array (even though it is not).
[0...2] is an array with one element which, at best, will be a Range<Int> from 0 through 2. You can't assign that to a slice containing, say, Ints.
x[0...2] on the other hand is (probably) a slice, and Sliceable only defines a get subscript, not a setter. So even if the types were more compatible - that is, if you tried x[0...2] = 0...2, which at least is attempting to replace a range within x with the values of a similarly-sized collection - it still wouldn't work.
edit: as #rintaro points out, Array does support a setter subscript for ranges – so if x were a range you could do x[0...2] = Slice(0...2) – but it has to be a slice you assign, so I'd still go with replaceRange.
If what you mean is you want to replace entries 0 through 2 with some values, what you want is replaceRange, as long as your collection conforms to RangeReplaceableCollection (which, for example, Array does):
var x = [0,1,2,3,4,5]
var y = [200,300,400]
x.replaceRange(2..<5, with: y)
// x is now [0,1,200,300,400,5]
Note, the replaced range and y don't have to be the same size, the collection will expand/contract as necessary.
Also, y doesn't have to an array, it can be any kind of collection (has to be a collection though, not a sequence). So the above code could have been written as:
var x = [0,1,2,3,4,5]
var y = lazy(2...4).map { $0 * 100 }
x.replaceRange(2..<5, with: y)
edit: so, per your edit, to in-place zero out an array of any size in one go, you can do:
var x = [1.0,2.0,0.0]
// range to replace is the whole array's range,
// Repeat just generates any given value n times
x.replaceRange(indices(x), with: Repeat(count: x.count, repeatedValue: 0.0))
Adjust the range (and count of replacing entries) accordingly if you want to just zero out a subrange.
Given your example Point class, here is how you could implement this behavior assuming it's backed by an array under the hood:
struct Point<T: FloatLiteralConvertible> {
private var _vals: [T]
init(dimensions: Int) {
_vals = Array(count: dimensions, repeatedValue: 0.0)
}
mutating func replaceRange
<C : CollectionType where C.Generator.Element == T>
(subRange: Range<Array<T>.Index>, with newElements: C) {
// just forwarding on the request - you could perhaps
// do some additional validation first to ensure dimensions
// aren't being altered...
_vals.replaceRange(subRange, with: newElements)
}
}
var x = Point<Double>(dimensions:3)
x.replaceRange(0...2, with: [1.1,2.2,3.3])
You need to implement subscript(InvervalType) to handle the case of multiple assignments like this. That isn't done for you automatically.