Swift optionals in class methods - swift

I am still relatively new to swift, so I am having some problems with the proper syntax. Here is my code for the class Date, which has the isLeapYear and daysInMonth methods. I am having problems with the optionals for these methods:
class Date {
var day, month, year : Int
init (day : Int, month : Int, year : Int) {
self.day = day
self.month = month
self.year = year
}
func isLeapYear(y : Int? = self.year) -> Bool {
var x = false
if y % 4 == 0 {x = true}
return x
}
//Returns the amount of days in a given month
func daysInMonth(month : Int? = self.month, year : Int? = self.year) -> Int? {
let _31_day_months = [1, 3, 5, 7, 8, 10, 12]
let _30_day_months = [4, 6, 9, 11]
if month == 2 {
if self.isLeapYear(y : year) {return 29} else {return 28}
}
else if _31_day_months.contains(month) {return 31}
else if _30_day_months.contains(month) {return 30}
else {return nil}
}
}
What I want to do with func isLeapYear(y : Int? = self.year) -> Bool is that when I call isLeapYear and y isn't specified, that it is automatically set to self.year. However I get the following error:
use of unresolved identifier 'self'
I also get the error
value of optional type 'Int?' must be unwrapped to a value of type
'Int'
I know I have to use !, but I don't know exactly how and where, I have tried doing if y! % 4 == 0, but that just seemed to make it worse.
I would also like to do the same thing for the method daysInMonth

Default values need to be constant at compile-time. You can't define them in terms of some other property. You need to check their values at runtime. In your example this would be:
func isLeapYear(y : Int? = nil) -> Bool {
var x = false
if (y ?? year) % 4 == 0 {x = true} // <== "?? year" meaning "y, or year if y is nil"
return x
}
Note that this is a very confusing API. You'd have to create a random Date instance in order to check something unrelated to that instance. Instead what I believe you really mean here is two methods; one static and one on the instance:
// Static method, called as Year.isLeapYear(xxxx)
static func isLeapYear(_ y: Int) -> Bool {
// Note that this is not the correct Gregorian Leap Year rule
return y % 4 == 0
}
// Instance method, called as year.isLeapYear()
func isLeapYear() -> Bool { Date.isLeapYear(year) }
Since you're new to Swift, it's worth noting: This should be a struct, not a class (it is a pure value that has no identity, and any two Dates with the same properties should be considered the same Date, which is what structs are for). And you should be careful calling it "Date" since that collides with the Foundation type of the same name.

Related

Check if array contains any even numbers and then show lowest even (or odd if no evens present)

In a function, I want to first check if the array given contains any numbers.
If there is an even number in the array I want to show the smallest number, and if there aren't any even numbers I want to at least show the smallest odd number whilst informing the user there are no even numbers.
The issue I have run into is: if there is a lower odd number in the array than the lowest even number it will ignore the fact that there is an even number in the array.
My progress to solving this was to first be able to determine the smallest number in an array
func smallestNumberInArray(listOfNumbers numbers: [Int]) -> Int {
var smallestNumber = numbers[0]
for x in numbers {
if x < smallestNumber {
smallestNumber = x
}
}
return smallestNumber
}
I then test it with smallestNumberInArray(listOfNumbers: [33, 44, 10, 22222, 099, 83]) which prints out 10
To test the even or odd logic I simply did
var listOfNumbers = [200, 3, 202]
for x in listOfNumbers {
if x % 2 == 0 {
print("\(x)")
}
}
Which printed out 200 and 202
I tried to combine this into 1 function
func checkSmallestEvenNumber(yourNumbers numbers: [Int]) -> String {
var smallestNumber = numbers[0]
var returnString = "Placeholder"
for x in numbers {
if x % 2 == 0 {
if x < smallestNumber {
smallestNumber = x
returnString = "The smallest even number is: \(smallestNumber)"
}
} else {
if x < smallestNumber && x % 2 != 0 {
smallestNumber = x
returnString = "No Evens, but the smallest odd is: \(smallestNumber)"
}
}
}
return returnString
}
So my function call checkSmallestEvenNumber(yourNumbers: [29, 33, 55, 22, 130, 101, 99]) returns The smallest even number is: 22 in this scenario, but if I change say the 55 to a 5 the return value is No Evens, but the smallest odd is: 5 when I want it to be 22 still.
Take advantage of higher level functions like filter with predicate isMultiple(of: 2) and min()
The result must be an optional to cover the case that the input array can be empty
func smallestNumberInArray(listOfNumbers numbers: [Int]) -> Int? {
if let smallestEvenNumber = numbers.filter({$0.isMultiple(of: 2)}).min() { return smallestEvenNumber }
return numbers.min()
}
smallestNumberInArray(listOfNumbers: [29, 33, 5, 22, 130, 101, 99])
Alternatively – and probably more efficient – first sort the array then return the first even number or the first number which must be odd or – if the array is empty – return nil
func smallestNumberInArray(listOfNumbers numbers: [Int]) -> Int? {
let sortedArray = numbers.sorted()
return sortedArray.first{$0.isMultiple(of: 2)} ?? sortedArray.first
}
A third way is first to partition the array in even and odd numbers and get the smallest number of the slices
func smallestNumberInArray(listOfNumbers numbers: [Int]) -> Int? {
var mutableNumbers = numbers
let firstOddIndex = mutableNumbers.partition(by: {$0.isMultiple(of: 2)})
return mutableNumbers[firstOddIndex...].min() ?? mutableNumbers[0..<firstOddIndex].min()
}
There are a number of ways to fix it. I made some tweaks to your code
func checkSmallestEvenNumber(yourNumbers numbers: [Int]) -> String {
guard !numbers.isEmpty else {
return "Empty array"
}
var smallestNumber = numbers[0]
var returnString = ""
for x in numbers {
if x % 2 == 0,
(smallestNumber % 2 != 0 || x < smallestNumber) {
smallestNumber = x
print(smallestNumber)
returnString = "The smallest even number is: \(smallestNumber)"
} else if x < smallestNumber,
smallestNumber % 2 != 0,
x % 2 != 0 {
smallestNumber = x
returnString = "No Evens, but the smallest odd is: \(smallestNumber)"
}
}
if returnString.isEmpty {
if smallestNumber % 2 == 0 {
returnString = "The smallest even number is: \(smallestNumber)"
} else {
returnString = "No Evens, but the smallest odd is: \(smallestNumber)"
}
}
return returnString
}
checkSmallestEvenNumber(yourNumbers: [0, 2, 23, 55, 130, 101, 55])
You should be throwing an error for odd numbers, not returning Strings.
extension Sequence where Element: BinaryInteger {
func lowestEvenNumber() throws -> Element {
switch (minima { $0.isMultiple(of: 2) }) {
case (_, let even?):
return even
case (let odd?, nil):
throw NoEvenNumbersError.onlyOdds(odd)
case (nil, nil):
throw NoEvenNumbersError<Element>.empty
}
}
}
enum NoEvenNumbersError<Integer: BinaryInteger>: Error {
case empty
case onlyOdds(Integer)
}
vadian's partitioning solution is good enough for your use case, but it's not applicable for all sequences. It should be. This is, and uses memory only for two elements:
public extension Sequence where Element: Comparable {
/// Two minima, with the second satisfying a partitioning criterion.
func minima(
partitionedBy belongsInSecondPartition: (Element) -> Bool
) -> (Element?, Element?) {
reduce(into: (nil, nil)) { minima, element in
let partitionKeyPath = belongsInSecondPartition(element) ? \(Element?, Element?).1 : \.0
if minima[keyPath: partitionKeyPath].map({ element < $0 }) ?? true {
minima[keyPath: partitionKeyPath] = element
}
}
}
}
I already marked #achu 's answer to be correct but as I mentioned in comments I figured it out moments after #achu answered.
Here is my less elegant solution: I separated the functionality into two functions and passed a function as a parameter in the main function.
func findLowestNumber(passingArray nums: [Int]) -> Int{
var small = nums[0]
for x in nums {
if x < small {
small = x
}
}
return small
}
I will use this mini function as a passing parameter later on
func checkSmallestEvenNumber(yourNumbers numbers: [Int]) -> String {
var parameterIntArray = numbers[0]
var allEvens = [Int]()
var str = "Placeholder"
for x in numbers {
if x % 2 != 0 {
str = "No Evens, however the lowest odd is \(findLowestNumber(passingArray: numbers))"
} else {
allEvens.append(x)
}
}
if allEvens.isEmpty != true {
str = "The lowest even is \(findLowestNumber(passingArray: allEvens))"
}
return str
}
What I did first was to check if any of the numbers were even. If none were then I created a string saying such but then passed the earlier function as a parameter to at least find the lowest odd.
The main fix was if there were any evens I appended them to a new array. Within this new array I again passed the earlier function to find the lowest number.
I'm sure this could be cleaned up (without using higher functions like map etc)
This function might not be "Swifty" (using higher order functions) but it will give a result with a single pass through the array:
func lowestEvenFromArray(_ intArray: [Int]) -> Int? {
var lowestEven: Int? = nil
var lowestOdd: Int? = nil
for value in intArray {
if value.isMultiple(of: 2) {
if value < (lowestEven ?? Int.max) {
lowestEven = value
}
} else if value < (lowestOdd ?? Int.max) {
lowestOdd = value
}
}
return lowestEven ?? lowestOdd
}
It should be the fastest of the answers given, all of which will make at least 2 passes through the array.

Swift iOS Map an Array Of Doubles, Convert them to Date, then Sort

I have a custom object that has a property of type Double. It gets initialized using Date().timeIntervalSince9170
Class MyObject {
dateAdded: Double?
}
let myObject1 = MyObject()
myObject1.dateAdded = Date().timeIntervalSince1970
//myObjec2 and more myObjects get initialized and everything added to the array below
var arr = [MyObject]()
arr.append(myObject1)
arr.append(myObject2)
arr.append...
I later have a different array that gets initialized with all the objects from the array above and I want to sort by the dateAdded so I map each object
var diffArr = [MyObject]()
diffArr.map { Date(timeIntervalSince1970: $0.dateAdded!)}
How can I then sort the diffArr after mapping it?
I would normally do this but compare doesn't work on Double
diffArr.sort { (d1, d2) -> Bool in
return d1.dateAdded?.compare(d2.dateAdded) == .orderedDescending
}
I looked at other q&a's but I couldn't find anything that does it all at once using Date
Dates are Comparable, so you can just use
diffArr.sort { return $0.dateAdded ?? 0.0 < $1.dateAdded ?? 0.0 }
(The force-unwrap is bad mojo. Can you change your structs so the dateAdded property is not optional?)
In my code I wrote the comparison to map nil date values to 0, so MyObject instances with nil dates would have very early dates.
You can try
op1:
diffArr.sort(by:>)
and implement https://developer.apple.com/documentation/swift/comparable protocol , if you want to use map for a result array not in-place
op2:
var dates = diffArr.map { Date(timeIntervalSince1970: $0.dateAdded!)}
dates.sort { (d1, d2) -> Bool in
return d1.compare(d2) == .orderedDescending
}

How to split or iterate over an Int without converting to String in Swift [duplicate]

This question already has answers here:
Break A Number Up To An Array of Individual Digits
(6 answers)
Closed 5 years ago.
I was wondering if there was a way in Swift to split an Int up into it's individual digits without converting it to a String. For example:
let x: Int = 12345
//Some way to loop/iterate over x's digits
//Then map each digit in x to it's String value
//Return "12345"
For a bit of background, I'm attempting to create my own method of converting an Int to a String without using the String description property or using String Interpolation.
I've found various articles on this site but all the ones I've been able to find either start with a String or end up using the String description property to convert the Int to a String.
Thanks.
Just keep dividing by 10 and take the remainder:
extension Int {
func digits() -> [Int] {
var digits: [Int] = []
var num = self
repeat {
digits.append(num % 10)
num /= 10
} while num != 0
return digits.reversed()
}
}
x.digits() // [1,2,3,4,5]
Note that this will return all negative digits if the value is negative. You could add a special case if you want to handle that differently. This return [0] for 0, which is probably what you want.
And because everyone like pure functional programming, you can do it that way too:
func digits() -> [Int] {
let partials = sequence(first: self) {
let p = $0 / 10
guard p != 0 else { return nil }
return p
}
return partials.reversed().map { $0 % 10 }
}
(But I'd probably just use the loop here. I find sequence too tricky to reason about in most cases.)
A recursive way...
extension Int {
func createDigitArray() -> [Int] {
if self < 10 {
return [self]
} else {
return (self / 10).createDigitArray() + [self % 10]
}
}
}
12345.createDigitArray() //->[1, 2, 3, 4, 5]
A very easy approach would be using this function:
func getDigits(of number: Int) -> [Int] {
var digits = [Int]()
var x = number
repeat{
digits.insert(abs(x % 10), at: 0)
x/=10
} while x != 0
return digits
}
And using it like this:
getDigits(of: 97531) // [9,7,5,3,1]
getDigits(of: -97531) // [9,7,5,3,1]
As you can see, for a negative number you will receive the array of its digits, but at their absolute value (e.g.: -9 => 9 and -99982 => 99982)
Hope it helps!

Understanding Swift Index, Range, Distance

I'm implementing an extension to Swift's CollectionType that provides the ability to find a subsequence in the collection and to find the range of that subsequence. My code that's working in a playground is this:
extension CollectionType where Generator.Element:Equatable, Index:ForwardIndexType, SubSequence.Generator.Element == Generator.Element {
func search<S: CollectionType where S.Generator.Element == Generator.Element, S.Index:ForwardIndexType>(pattern: S) -> Self.Index? {
return self.lazy.indices.indexOf{
self[$0..<self.endIndex].startsWith(pattern)
}
}
func rangeOf<S: CollectionType where S.Generator.Element == Generator.Element, S.Index:ForwardIndexType, Index:ForwardIndexType>(pattern: S) -> Range<Index>? {
if let start = self.search(pattern) {
var end = start
for _ in pattern.startIndex..<pattern.endIndex {
end = end.advancedBy(1)
}
return start..<end
} else {
return nil
}
}
}
Simple playground test cases are these:
let fibs = [1, 1, 2, 3, 5, 8, 13]
if let fidx = fibs.search([3, 5]) {
print(fibs[..<fidx]) // prints "[1, 1, 2]\n"
print(fidx..<fidx.advancedBy([1,1,5].count)) // prints "3..<6\n"
}
if let rng = fibs.rangeOf([5,8,13]) {
print(rng) // prints "4..<7\n"
}
However, in the rangeOf function, instead of the loop
for _ in pattern.startIndex..<pattern.endIndex {
end = end.advancedBy(1)
}
I expected to be able to use the statement
end = start.advancedBy(pattern.count, limit: self.endIndex)
or perhaps
end = start.advancedBy(pattern.endIndex - pattern.startIndex, limit: self.endIndex)
(I do recognize that the limit parameter is redundant; omitting it makes no difference in the following.) Neither of those last two compile, with the error cannot invoke 'advancedBy' with an argument list of type '(S.Index.Distance, limit: Self.Index)'. My question is, why isn't either of these two forms acceptable? (I suppose there are other valid questions as to whether I've properly formed the constraints on types for the extension and for the functions, but since the one version works I'm ignoring that for now.)
end = start.advancedBy(pattern.count, limit: self.endIndex)
does not compile because the collections self and pattern need
not have the same Index type.
It compiles if you add a constraint S.Index == Index to the rangeOf() method.

Swift : Custom operator to update dictionary value

Is there an elegant way to make a custom operator that updates a dictionary value?
More specifically, I want a prefix operator that increments the integer value corresponding to a given key:
prefix operator +> {}
prefix func +> //Signature
{
...
}
var d = ["first" : 10 , "second" : 33]
+>d["second"] // should update d to ["first" : 10 , "second" : 34]
This is feasible using the functional way. For example, to calculate the frequencies of elements in an array:
func update<K,V>(var dictionary: [K:V], key: K, value: V) -> [K:V] {
dictionary[key] = value
return dictionary
}
func increment<T>(dictionary: [T:Int], key: T) -> [T:Int] {
return update(dictionary, key: key, value: dictionary[key].map{$0 + 1} ?? 1)
}
func histogram<T>( s: [T]) -> [T:Int] {
return s.reduce([T:Int](), combine: increment)
}
let foo = histogram([1,4,3,1,4,1,1,2,3]) // [2: 1, 3: 2, 1: 4, 4: 2]
But I am trying to do the same thing using a custom operator
var d = ["first" : 10 , "second" : 33]
d["second"]?++
The operator could be implemented like this:
prefix operator +> {}
prefix func +> <I : ForwardIndexType>(inout i: I?) {
i?._successorInPlace()
}
var dict = ["a":1, "b":2]
+>dict["b"]
dict // ["b": 3, "a": 1]
Although I'm not sure how it would give you a frequencies function - I mean, if it's building a dictionary, it's not going to have any keys to begin with, so there won't be anything to increment. There are a bunch of cool ways to do it, though. Using the postfix ++, you can do this:
extension SequenceType where Generator.Element : Hashable {
func frequencies() -> [Generator.Element:Int] {
var result: [Generator.Element:Int] = [:]
for element in self {
result[element]?++ ?? {result.updateValue(1, forKey: element)}()
}
return result
}
}
Airspeed Velocity tweeted another cool way:
extension Dictionary {
subscript(key: Key, or or: Value) -> Value {
get { return self[key] ?? or }
set { self[key] = newValue }
}
}
extension SequenceType where Generator.Element : Hashable {
func frequencies() -> [Generator.Element:Int] {
var result: [Generator.Element:Int] = [:]
for element in self { ++result[element, or: 0] }
return result
}
}
Or, using an undocumented function:
extension SequenceType where Generator.Element : Hashable {
func frequencies() -> [Generator.Element:Int] {
var result: [Generator.Element:Int] = [:]
for el in self {result[el]?._successorInPlace() ?? {result[el] = 1}()}
return result
}
}
First, look for a way to do it using functions (not custom operators). You want a function that takes a reference to an item (from a dictionary) and updates its value... that calls for an inout parameter type.
func increment(inout n: Int) {
n++
}
var d = ["first" : 10 , "second" : 33]
increment(&d["first"]!)
print(d) // -> "[first: 11, second: 33]"
You don't have to care about the value being in a dictionary — inout takes any kind of reference and updates it directly. (This even goes for computed properties. You can pass one inout and it'll correctly go through the setter and getter as it reads and writes values.) And because you don't have to care about the dictionary, you don't really need to be generic — if you want a function that works on dictionaries with Ints, just make a function that works on Ints and let inout do the rest.
Now, custom operators are just functions, so make an operator of your function:
prefix operator +> {}
prefix func +>(inout n: Int) {
n++
}
You can't use exactly the syntax you were asking for to invoke it, though: dictionary lookups always result in Optional types, so you have to unwrap.
+>d["second"] // error
+>d["second"]! // but this works — operators automatically make params inout as needed
print(d) // -> "[first: 11, second: 34]"
This is a little uglier than you probably are looking for, but you can accomplish it using an unsafe mutable pointer in a generic overloaded operator:
prefix operator +> {}
prefix func +><T>( value:UnsafeMutablePointer<T?> )
{
print( value.memory )
if let intValue = value.memory as? Int {
value.memory = (intValue + 1) as? T
}
}
var d = ["first" : 10 , "second" : 33]
print( d["second"] ) // Optional(33)
+>(&d["second"])
print( d["second"] ) // Optional(34)