Converting UnitVolume.metricCups to a fraction in swift 4 - swift

Is it possible to convert the format that comes out of converted(to: UnitVolume.metricCups) into a fraction so the answer is read just like you would from say a cookbook etc.
Example after the conversion is complete I get an answer of 1.5 metric cups, but I would like to see it as 1 1/2 or say 0.333 as 1/3 cup.
Swift documentation doesn't really mention any steps for this that I'm aware of. Thank you.
This is what the storyboard looks like:
let millimeters = Measurement(value: waterResult, unit: UnitVolume.milliliters)
let resultWaterConversion = millimeters.converted(to:UnitVolume.metricCups)
cupsWater.text = "\(resultWaterConversion)"

I was able to solve my issue by using a switch and a little modification with the string values eg "3/4" to get it just right for my needs.
Here is the code i used:
`// MARK:- Conversion to display rice amount in the correct format for readability
let resultRiceInteger = Int(resultRiceConversion.value)
let resultRiceFraction = Int(100 * (resultRiceConversion.value - Double(resultRiceInteger))) // To avoid bad effects due to Double
var decimalTextR = ""
switch resultRiceFraction {
case 0...9 : decimalTextR = "" // Now, approximate
case 10 : decimalTextR = "1/10" // First when we are very close to real fraction
case 11 : decimalTextR = "1/9"
case 12...13 : decimalTextR = "1/8"
case 14...15 : decimalTextR = "1/7"
case 16...18 : decimalTextR = "1/6"
case 19...22 : decimalTextR = "1/5"
case 23...29 : decimalTextR = "1/4"
case 30...40 : decimalTextR = "1/3"
case 41...60 : decimalTextR = "1/2"
case 61...72 : decimalTextR = "2/3"
case 73...79 : decimalTextR = "3/4"
case 90...110 : decimalTextR = "1"
default : decimalTextR = ""
}
cupsWater.text = "\(resultRiceInteger) and \(decimalTextR)" // UILabel displayed on my stored board.
let cupsRiceText = resultRiceConversion.value > 1 ? "cups" : "cup"
if resultRiceInteger > 0 {
cupsRice.text = "\(resultRiceInteger) \(decimalTextR) \(cupsRiceText)" // UILabel displayed on my stored board.
} else {
cupsRice.text = "\(decimalTextR) \(cupsRiceText)"
}`

Related

Efficient algorithm to split a string based on multiple string delimiters

I would like to know if there is an efficient way of splitting a string into multiple strings based on delimiters that are also strings.
Eg. updateStr = "23+45 = 56 0" , delimiters = ["+"," ","="]
Result = [23,45,56,0]
I tried the following code in swift:
for i in 0..<delimiter.count {
let res = updateStr.components(separatedBy: delimiter[i])
updateStr = res.joined(separator: "unique%")
}
splitTxt = updateStr.components(separatedBy: "unique%")
This works, but as the delimiters will be received dynamically I want a better approach.
Are there any efficient ways to avoid multiple loops to solve this?
An algorithm with more efficient solution that doesn't involve swift instance methods would also be appreciated.
Thanks for the answers but
To be clearer, I don't just want characters but strings as delimiters:
Eg2. updateStr = "I like playing with friends" , delimiters = ["li"," "la","ie"]
Result = ["I ","ke p","ying with fr","nds"]
The efficient way to do this sort of thing is with a Set:
let equation = "23+45 = 56 0"
let delimiters : [Character] = ["+"," ","="]
let setOfSeparators = Set(delimiters)
let result = equation.split {setOfSeparators.contains($0)}
print(result)
That's efficient because contains on a Set is extremely fast, so that cost is negligible and we are looping implicitly through the original string just once.
On the other hand, you could take advantage of the Cocoa CharacterSet class. For that, I would say:
let equation = "23+45 = 56 0"
let delimiters = ["+"," ","="]
let characterSet = CharacterSet(charactersIn: delimiters.joined())
let result = equation.components(separatedBy: characterSet).filter {!$0.isEmpty}
print(result)
Another fun way is to use a Scanner (these are underutilized in my opinion):
let equation = "23+45 = 56 0"
let delimiters = ["+"," ","="]
let characterSet = CharacterSet(charactersIn: delimiters.joined())
let scanner = Scanner(string: equation)
var result = [String]()
while let word = scanner.scanUpToCharacters(from: characterSet) {
result.append(word)
scanner.scanCharacters(from: characterSet)
}
print(result)
One of the components(separatedBy:) overloads will handle this automatically using a CharacterSet:
let delimiters = ["+"," ","="].compactMap(UnicodeScalar.init)
let splitTxt = updateStr.components(separatedBy: CharacterSet(delimiters))
NSRegularExpression provides the facility to split on general regular expressions, so this would enable splitting on a finite set of string delimiters using a delim1|delim2|delim3 regex. The following split operation does this job:
static func stringSubrange(str : String, st : Int, en : Int) -> String
{ var result : [Character] = [Character]()
var count : Int = 0
for index in str.indices
{ let c : Character = str[index]
count = count + 1
if count >= st && count <= en
{ result.append(c) }
else if count > en
{ return String(result) }
}
return String(result)
}
static func split(str: String, pattern: String) -> [String]
{ let rge = NSRange(location: 0, length: str.utf16.count)
let regexp = try! NSRegularExpression(pattern: pattern)
let pred = regexp.matches(in: str, options: [], range: rge)
var result : [String] = [String]()
var prev : Int = 1;
for p in pred
{ let range = p.range
let splitString = Ocl.stringSubrange(str: str, st: prev, en: range.location)
prev = range.location + range.length + 1
if splitString.count > 0
{ result.append(splitString) }
}
if prev < str.count
{ result.append(Ocl.stringSubrange(str: str, st: prev, en: str.count)) }
return result
}

Different func parameters at the same time

To learn about dictionaries I am trying to use a single function with arguments for different operations.
This function is actually the logic of five similar functions that were independently called by five individual cells at the time to do stuff like calculating a difference. Not very optimized I thought.
Here is the logic now, calling the function with different parameters at the same time:
let milkUSD : Double = 3.00
let chocolateUSD : Double = 4.50
let reduction1 : Double = 0.50
let reduction2 : Double = 0.30
var prices : [String : Double] = ["p1": milkUSD, "p2": chocolateUSD]
var reductions : [String : Double] = ["r1": reduction1, "r2": reduction2]
func calculateReduction(_ price: String, _ reduction: String) {
let price = prices[price]
guard price != nil else { return }
let reduction = reductions[reduction]
guard reduction != nil else { return }
let result = price! - reduction!
print(result)
}
//called at the same time:
calculateReduction("p1", "r1") //prints 2.5
calculateReduction("p2", "r2") //prints 4.2
It works in the playground but will using a function like this cause me problems in my app when it will be called at the same time to process more complex operations and with value changing variables? Or do I simply underestimate computers haha?

It is possible to do "if \(var1) = 0"?

var a = 0
(... up to var z = 0)
let letterchoosedbyplayer:String = LetterChoosed.text!
"LetterChoosed" is a textbox. The player enter a letter in this textbox.
I store the value in the variable "letterchoosedbyplayer".
Then i want to check if the variable called 'letterchoosedbyplayer' (it must be a letter of the alphabet) is equal to 1.
How can i do that?
I want to do that :
if \(letterchoosedbyplayer) = 1 {
}
Last Edit : All my code
let letterchoosedbyplayer:String = LetterChoosed.text!
if Int(letterchoosedbyplayer) == 1 {
print("vous avez perdu")
}
else {
switch letterchoosedbyplayer {
case "a":
print("lettre \(letterchoosedbyplayer) choisie")
a = 1
case "b":
print("lettre \(letterchoosedbyplayer) choisie")
b = 1
default:
print("cas défaut")
}
}
\() is used to append any object in a string. I don't think you can use this for your need
Try
if let letterchoosedbyplayer = LetterChoosed.text where letterchoosedbyplayer == "1" {
}
You could include the "1" case in the switch statement:
let letterchoosedbyplayer = LetterChoosed.text
if let lettrechoisie = letterchoosedbyplayer where !lettrechoisie.isEmpty {
switch lettrechoisie {
case "1": print("vous avez perdu")
case "a":
print("lettre \(lettrechoisie) choisie")
a = 1
case "b":
print("lettre \(lettrechoisie) choisie")
b = 1
default:
print("cas défaut")
}
}
Note that Int(letterchoosedbyplayer)! == 1 and letterchoosedbyplayer == "1" is the same thing.
Edit:
For your purpose you might use a dictionary rather than more than 20 single variables
var letterDict : [String : Int] = ["a" : 0, "b" : 0, "c" : 0, ... "z" : 0]
You can set a variable to 1 for example
letterDict["f"] = 1
Then you can check
if let lettrechoisie = letterchoosedbyplayer where !lettrechoisie.isEmpty {
let value = letterDict[lettrechoisie]!
if value == 1 {
// do something
} else {
// do something else
}
}
That avoids also a huge switch statement.

Binary value of a Character in pure Swift

I need to convert a character in its binary string.
Ex : C = 34 = "1000011"
My work in progress look like this. It's work only for "C" character :
import Foundation
func charToBin(c:Character) -> String {
let binaire = 34
return String(binaire, radix: 2)
}
let c:Character = "C"
let b = charToBin(c)
Thank you for your help :
I solved my problem with this code :
func stringToBinaryString (myString:String) -> String {
// Array of characters
let characterArray = [Character](myString.characters)
// Array of asccii value
let asciiArray = characterArray.map({String($0).unicodeScalars.first!.value})
// Array of binary value
let binaryArray = asciiArray.map ({ String($0, radix: 2)})
// Reduce in a String
let r = binaryArray.reduce("",combine: {$0 + " " + $1})
return r
}
// Sample use :
let r = stringToBinaryString("CC")

Calculate count of years

I have a String data that stores date. Example:
let dates = ["1-Jan-2015", "1-Feb-2015", "20-Mar-2014", "15-Apr-2014", "12-May-2013", "23-Jun-2012"]
I need to do a count of how many times did that year occurs, and then store it. So what I require would be something like that
let years = ["2015" : 2, "2014" : 2, "2013" : 1, "2012" : 1]
I would like to avoid hard coding it for future growth. Meaning say if I have Year 2020, I cannot be hard coding all the years to store these values.
So the problem here is I've got no idea how should I do this on the overview. In addition, how do I convert the String format to date?
let dates = ["1-Jan-2015", "1-Feb-2015", "20-Mar-2014", "15-Apr-2014", "12-May-2013", "23-Jun-2012"]
// map the last 4 characters of your string
let years = dates.map{String($0.characters.suffix(4))}
// create a dictionary to store tue frequency
var frequencies:[String:Int] = [:]
// loop through the years
for year in years {
// increase it
frequencies[year] = (frequencies[year] ?? 0) + 1
}
let sortedFrequencies = frequencies.sort{ $0.0 < $1.0 }
print(sortedFrequencies) // [("2012", 1), ("2013", 1), ("2014", 2), ("2015", 2)]\n"
I have created the following solution. Use the following function and it will give you the following result in the screenshot
/// This function will return the array as per your requirement
func getyears(dates: NSArray) -> NSArray
{
var year = [String]()
let newdates = dates
var countvalue = 0
for i in dates {
let x = i.stringByReplacingOccurrencesOfString("-", withString: "")
let startIndex = x.endIndex.advancedBy(-4)
let lastFourDigitsOfdate = x.substringFromIndex(startIndex)
for xm in newdates
{
let xy = xm.stringByReplacingOccurrencesOfString("-", withString: "")
let startIndex1 = xy.endIndex.advancedBy(-4)
let lastFourDigitsOfdate1 = xy.substringFromIndex(startIndex1)
if lastFourDigitsOfdate == lastFourDigitsOfdate1
{
countvalue = countvalue + 1
}
}
year.append("\(lastFourDigitsOfdate) : \(countvalue)")
countvalue = 0
}
return getUniqArrayData(year)
}
// This function will be required to get an unque array
func getUniqArrayData<S: SequenceType, E: Hashable where E==S.Generator.Element>(source: S) -> [E] {
var seen: [E:Bool] = [:]
return source.filter { seen.updateValue(true, forKey: $0) == nil }
}
let dates = ["1-Jan-2015", "1-Feb-2015", "20-Mar-2014", "15-Apr-2014", "12-May-2013", "23-Jun-2012"]
//Calling the above function
getyears(dates)
Hope this will be helpful.