Swift variable accessibility - swift2

I am doing this for a class, so I am not looking for someone to code this for me, just for a little guidance. Using Swift3 in Xcode 8. I fixed the previous errors and I think I'm making progress but...
class Cat {
var catName, catBreed, catColor: String
var catAge, catWeight: Int
init(name:String, age:Int, weight:Int, breed:String, color:String)
{
catName = name
catAge = age
catWeight = weight
catBreed = breed
catColor = color
}
func calculateAge (catAge: Int) -> Int
{
var humanYears = 0
if catAge == 1 {
humanYears = 15
} else if catAge == 2 {
humanYears = 24
} else if catAge > 2 {
humanYears = (24 + (catAge * 4))
}
print ("Your cat is \(humanYears) human years old!")
return humanYears
}
func createCats(name: String, age: Int, weight: Int, breed: String, color: String) -> String
{
let humanYears = calculateAge(catAge: age)
let catInfo : String = "\(name) is a \(color) \(breed) who weights \(weight) named \(name), and he is \(humanYears) human years old."
print (catInfo)
return catInfo
}
}
Cat.createCats()
I get an error at Cat.createCats() stating use of instance member 'createCats' on type 'Cat'; did you mean to use a value of type 'Cat' instead?
I have tried putting Cat in the (), I have tried naming all of my variables in there...

As I see in your code , you are re-declaring the variable "humanYears".
One is immediate after Class and second is in the function "calculateAge" . Edit your function "calculate" as below :
func calculateAge (catAge: Int) -> Int {
if catAge == 1 {
humanYears = 15
} else if catAge == 2 {
humanYears = 24
} else if catAge > 2 {
humanYears = (24 + (catAge * 4))
}
return humanYears
}

I figured out what I was doing wrong, thanks to you guys and another post on Stack Overflow that I searched up. Just in case it helps anyone here, I will post my final code below. My biggest issue was that I was trying to call the function before I created an instance of the class. This is not the finished version of the solution, but I was excited that I got it working so I wanted to post it.
Thanks again for all of your help,
class Cat
{
func calculateAge (catAge: Int) -> String
{
var humanYears = 0
if catAge == 1 {
humanYears = 15
} else if catAge == 2 {
humanYears = 24
} else if catAge > 2 {
humanYears = (24 + (catAge * 4))
}
return "Your cat is \(humanYears) human years old!"
}
func createCats(name: String = "Fluffy", age: Int = 1, weight: Int = 3, breed: String = "tabby", color: String = "brown") -> String
{
var catInfo : String
let humanYears = calculateAge(catAge: age)
catInfo = "\(name) is a \(color) \(breed) who weights \(weight) pounds named \(name), and he is \(humanYears) human years old."
print (catInfo)
return catInfo
}
}
let firstCat = Cat()
firstCat.createCats()
let secondCat = Cat()
secondCat.createCats(name: "bob")

Related

Sorting Strings by Character and Length

In my Android app, I am trying to sort Bus route tags in order 1, 2, 3..etc.
For that I am using this
Collections.sort(directions, Comparator { lhs, rhs ->
var obj1 = lhs.short_names.firstOrNull() ?: ""
var obj2 = rhs.short_names.firstOrNull() ?: ""
if (obj1 === obj2) {
obj1 = lhs.headsigns.firstOrNull() ?: ""
obj2 = rhs.headsigns.firstOrNull() ?: ""
if (obj1 === obj2) {
return#Comparator 0
}
obj1.compareTo(obj2)
} else {
obj1.compareTo(obj2)
}
The issue I am having is this sorts them, but will run into the issue of
1, 2, 3, 30, 31, 4, 5
How should I change this to get the correct ordering.
If you need just a simple number comparison you can do it like that.
directions.sortWith(Comparator { lhs, rhs ->
val i1 = lhs.toInt()
val i2 = rhs.toInt()
when {
i1 < i2 -> -1
i1 > i2 -> 1
else -> 0
}
})
As hotkey pointed out the code above can be replaced with almost identical implementation that looks much simplier.
directions.sortBy { it.toInt() }
The general version of this algorithm is called alphanum sorting and described in details here. I made a Kotlin port of this algorithm, which you can use. It's more complicated than what you need, but it will solve your problem.
class AlphanumComparator : Comparator<String> {
override fun compare(s1: String, s2: String): Int {
var thisMarker = 0
var thatMarker = 0
val s1Length = s1.length
val s2Length = s2.length
while (thisMarker < s1Length && thatMarker < s2Length) {
val thisChunk = getChunk(s1, s1Length, thisMarker)
thisMarker += thisChunk.length
val thatChunk = getChunk(s2, s2Length, thatMarker)
thatMarker += thatChunk.length
// If both chunks contain numeric characters, sort them numerically.
var result: Int
if (isDigit(thisChunk[0]) && isDigit(thatChunk[0])) {
// Simple chunk comparison by length.
val thisChunkLength = thisChunk.length
result = thisChunkLength - thatChunk.length
// If equal, the first different number counts.
if (result == 0) {
for (i in 0..thisChunkLength - 1) {
result = thisChunk[i] - thatChunk[i]
if (result != 0) {
return result
}
}
}
} else {
result = thisChunk.compareTo(thatChunk)
}
if (result != 0) {
return result
}
}
return s1Length - s2Length
}
private fun getChunk(string: String, length: Int, marker: Int): String {
var current = marker
val chunk = StringBuilder()
var c = string[current]
chunk.append(c)
current++
if (isDigit(c)) {
while (current < length) {
c = string[current]
if (!isDigit(c)) {
break
}
chunk.append(c)
current++
}
} else {
while (current < length) {
c = string[current]
if (isDigit(c)) {
break
}
chunk.append(c)
current++
}
}
return chunk.toString()
}
private fun isDigit(ch: Char): Boolean {
return '0' <= ch && ch <= '9'
}
}
To use this Comparator just call
directions.sortWith(AlphanumComparator())
If you don't need it to be coded in Kotlin you can just take an original Java version on Dave Koelle's page. And the Kotlin version of the algorithm can be also found on GitHub.

I need to make sure my town's population won't decrement less than 0, But I am having trouble writing this code with out Bugs

class Zombie: Monster {
var walksWithLimp = true
final override func terrorizeTown() {
var message : String
town?.changePopulation(-10)
super.terrorizeTown()
if changePopulation = 0 {
message = "Cannot Decrement"
}
print(messsage)
}
func changeName(name: String, walksWithLimp: Bool) {
self.name = name
self.walksWithLimp = walksWithLimp
}
}
My errors are on the if statement and the message.
You are using using the '=' operator instead of the '=='.
Best if you use '<=' 0 to cover negative values.
if changePopulation <= 0
{
message = "Cannot Decrement"
}
Since you asked to ensure that the population doesn't drop below zero, then Town.changePopulation(i:Int) must not do this check. This can't be done unless you have a way to query the town's population. Let's assume Town has a property called population. if so: This will work
class Zombie: Monster {
var walksWithLimp = true
final override func terrorizeTown() {
var message : String
if let town = town { // Ensure town exists
var populationChange = 10
if town.population < populationChange {
populationChange = town.population
}
town.changePopulation(-populationChange)
super.terrorizeTown()
if populationChange == 0 {
message = "Cannot Decrement"
print(messsage)
}
} else {
message = "No Town Available"
print(messsage)
}
}
func changeName(name: String, walksWithLimp: Bool) {
self.name = name
self.walksWithLimp = walksWithLimp
}
}
Change this:
if changePopulation = 0
To this:
if changePopulation == 0
The first expression sets changePopulation to 0. The second evaluates as a boolean 0 or 1 depending on whether or not changePopulation is equal to 0. This is a common mistake; always be careful with those equal signs in languages like this.

How to remove multiple spaces in Strings with Swift 2

Until Swift 2 I used this extension to remove multiple whitespaces:
func condenseWhitespace() -> String {
let components = self.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).filter({!Swift.isEmpty($0)})
return " ".join(components)
}
but with Swift 2 now I get the error
Cannot invoke 'isEmpty' with an argument list of type '(String)'
How could I now remove multiple spaces with Swift 2?
Thnx!
In Swift 2, join has become joinWithSeparator and you call it on the array.
In filter, isEmpty should be called on the current iteration item $0.
To replace whitespaces and newline characters with unique space characters as in your question:
extension String {
func condenseWhitespace() -> String {
let components = self.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
return components.filter { !$0.isEmpty }.joinWithSeparator(" ")
}
}
let result = "Hello World.\nHello!".condenseWhitespace() // "Hello World. Hello!"
Because your function does not take any parameter you could make it a property instead:
extension String {
var condensedWhitespace: String {
let components = self.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
return components.filter { !$0.isEmpty }.joinWithSeparator(" ")
}
}
let result = "Hello World.\nHello!".condensedWhitespace // "Hello World. Hello!"
In Swift 3 there's even more changes.
Function:
extension String {
func condenseWhitespace() -> String {
let components = self.components(separatedBy: NSCharacterSet.whitespacesAndNewlines)
return components.filter { !$0.isEmpty }.joined(separator: " ")
}
}
let result = "Hello World.\nHello!".condenseWhitespace()
Property:
extension String {
var condensedWhitespace: String {
let components = self.components(separatedBy: NSCharacterSet.whitespacesAndNewlines)
return components.filter { !$0.isEmpty }.joined(separator: " ")
}
}
let result = "Hello World.\nHello!".condensedWhitespace
In Swift 4.2 NSCharacterSet is now CharacterSet, and you can omit and use dot syntax:
extension String {
func condenseWhitespace() -> String {
let components = self.components(separatedBy: .whitespacesAndNewlines)
return components.filter { !$0.isEmpty }.joined(separator: " ")
}
}
let result = "Hello World.\nHello!".condenseWhitespace() // "Hello World. Hello!"
Split string to array and then join again in not memory efficient. Its Takes lot of memory. The best way in this case is to scan the given string and perform operations on that. Regular Expression is the advance way to scan a text. For the above conclusion the the solution is given below:
Swift 4.x
extension String {
func removeExtraSpaces() -> String {
return self.replacingOccurrences(of: "[\\s\n]+", with: " ", options: .regularExpression, range: nil)
}
}
Usages
let startingString = "hello world! \n\n I am here!"
let processedString = startingString.removeExtraSpaces()
print(processedString)
Output:
processedString => "hello world! I am here!"
You can Do more according to your own requirements but thing I am pointing out here is to use regular expressions with string rather then create arrays which will consume lot of memory.
Cleanest version. Documented, memory efficient, extremely easy to use.
extension String {
/// Returns a condensed string, with no extra whitespaces and no new lines.
var condensed: String {
return replacingOccurrences(of: "[\\s\n]+", with: " ", options: .regularExpression, range: nil)
}
/// Returns a condensed string, with no whitespaces at all and no new lines.
var extraCondensed: String {
return replacingOccurrences(of: "[\\s\n]+", with: "", options: .regularExpression, range: nil)
}
}
Usage:
let a = " Hello\n I am a string ".condensed
let b = " Hello\n I am a string ".extraCondensed
Output:
a: "Hello I am a string"
b: "HelloIamastring"
SWIFT 3: Cleaner version
extension String {
var condensedWhitespace: String {
let components = self.components(separatedBy: .whitespacesAndNewlines)
return components.filter { !$0.isEmpty }.joined(separator: " ")
}
}
Here is mine: How it's actually worked.
extension String {
func removeExtraSpaces() -> String {
var data = ""
var numberOfSpace = 0
let items = self.getComponents(separatedBy: " ")
for item in items{
if item == " "{
numberOfSpace = numberOfSpace + 1
}else{
numberOfSpace = 0
}
if numberOfSpace == 1 || numberOfSpace == 0 {
data = data + item
//data.append(item)
}
}
return data
}
}
Usages
var message = "What is the purpose of life?"
message = message.removeExtraSpaces()
print(message)
Output:
What is the purpose of life?
var str = "Hello World.\nHello!"
if let regex = try? NSRegularExpression(pattern: "\\s+", options:NSRegularExpression.Options.caseInsensitive)
{
str = regex.stringByReplacingMatches(in: str, options: [], range: NSMakeRange(0, str.count), withTemplate: " ")
}

Order an array of objects by the value of their enums in swift

I have an array of CLBeacon objects which all have a property .proximity.
I want to order the array by this property which contains the CLProximity enum. So I want all objects to be in order IMMEDIATE, NEAR, FAR, UNKNOWN.
Is there a way to do this neatly without resorting to a bunch of if statements?
If you define a (computed read-only) property sortIndex of CLProximity
extension CLProximity {
var sortIndex : Int {
switch self {
case .Immediate:
return 0
case .Near:
return 1
case .Far:
return 2
case .Unknown:
return 3
}
}
}
then you can sort an array of beacons with
let sortedBeacons = sorted(beacons) { $0.proximity.sortIndex < $1.proximity.sortIndex }
If .Unknown is the only CLProximity value that needs
"special treatment" and all other possible values are in the desired
relative order then you can simplify the property definition to
extension CLProximity {
var sortIndex : Int {
return self == .Unknown ? Int.max : rawValue
}
}
You can use custom comparator and sort an array using that ,
You will "say" for all objects that has "unknown" proximity are "bigger" than others
var sortedArray = persons.sortedArrayUsingComparator {
(obj1, obj2) -> NSComparisonResult in
if obj1.proximity.rawValue == obj12.proximity.rawValue {
return NSComparisonResult.OrderedSame
} else if obj1.proximity == .UNKNOWN || obj1.proximity.rawValue > obj12.proximity.rawValue {
return NSComparisonResult.OrderedDescending
}
return NSComparisonResult.OrderedAscending
}
Based on what Julia wrote above I had cobbled this together:
self.beacons = beacons as! [CLBeacon]
var tempBeacons = zip(self.beacons, self.beacons.map({
(b: CLBeacon) -> Int in
if b.proximity == .Immediate {
return 0
} else if b.proximity == .Near {
return 1
} else if b.proximity == .Far {
return 2
} else if b.proximity == .Unknown {
return 3
}
return 0
}))
self.beacons = sorted(tempBeacons, {$0.1 < $1.1}).map({ $0.0 })
Thanks all!
Based on #Martin answer.
You can also create Int enum and assign value to it and then sort it like below.
enum myEnum: Int {
case A = 0
case B = 1
case C = 2
case D = 3
}
let myData : [myEnum:[String]] = [.C:["3"],.D:["4"],.B:["2"],.A:["1"]]
print(myData.first?.key)
let newData = myData.sorted(by: { $0.key.rawValue < $1.key.rawValue })
print(newData.first?.key)
Hope this helps
Swift 5
Now you can just add Comparable to your enum and it respects the order
enum ContainerLevel: Comparable {
case empty
case almostEmpty
case halfFull
case almostFull
case full
}
//Are we running low?
let needMoreCoffee = coffeeMugLevel > .halfFull
print(needMoreCoffee) //true
Link to more Code examples

Word Count in Swift [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
What is a more elegant way of writing a simple word count function in Swift?
//Returns a dictionary of words and frequency they occur in the string
func wordCount(s: String) -> Dictionary<String, Int> {
var words = s.componentsSeparatedByString(" ")
var wordDictionary = Dictionary<String, Int>()
for word in words {
if wordDictionary[word] == nil {
wordDictionary[word] = 1
} else {
wordDictionary.updateValue(wordDictionary[word]! + 1, forKey: word)
}
}
return wordDictionary
}
wordCount("foo foo foo bar")
// Returns => ["foo": 3, "bar": 1]
Your method was pretty solid, but this makes a couple improvements. I store the value count using Swifts "if let" keyword to check for an optional value. Then I can use count when updating the dictionary. I used the shorthand notation for updateValue (dict[key] = val). I also split the original string on all whitespace instead of just a single space.
func wordCount(s: String) -> Dictionary<String, Int> {
var words = s.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
var wordDictionary = Dictionary<String, Int>()
for word in words {
if let count = wordDictionary[word] {
wordDictionary[word] = count + 1
} else {
wordDictionary[word] = 1
}
}
return wordDictionary
}
I don't think this is more elegant because the readability is terrible and it requires and extension on Dictionary but it was really fun to write and shows you the potential power of swift:
extension Dictionary {
func merge(with other: [KeyType:ValueType], by merge: (ValueType, ValueType) -> ValueType) -> [KeyType:ValueType] {
var returnDict = self
for (key, value) in other {
var newValue = returnDict[key] ? merge(returnDict[key]!, value) : value
returnDict.updateValue(newValue, forKey: key)
}
return returnDict
}
}
func wordCount(s: String) -> [String:Int] {
return s.componentsSeparatedByString(" ").map {
[$0: 1]
}.reduce([:]) {
$0.merge(with: $1, +)
}
}
wordCount("foo foo foo bar")
I do think that merge extension would be useful in other circumstances though
Couldn't find any traces of a Counter type class in the Collections library.
You can improve the code slightly by using optional chaining.
func wordCount(s: String) -> Dictionary<String, Int> {
var words = s.componentsSeparatedByString(" ")
var wordDictionary = Dictionary<String, Int>()
for word in words {
if wordDictionary[word]? {
wordDictionary[word] = wordDictionary[word]! + 1
} else {
wordDictionary[word] = 1
}
}
return wordDictionary
}
wordCount("foo foo foo bar")
maybe not elegant but was fun to implement
let inString = "foo foo foo bar"
func wordCount(ss: String) -> Dictionary<String, Int> {
var dict = Dictionary<String, Int>()
var tempString = "";var s = ss + " "
for each in s{
if each == " "{ if dict[tempString] {
var tempNumber = Int(dict[tempString]!)
dict[tempString] = Int(tempNumber+1)
tempString = ""
} else {dict[tempString] = 1;tempString = ""}
} else {
tempString += each}}
return dict
}
println(wordCount(inString))

Resources