Indexes as Ints in Swift - ios

I have the following code which I've commented:
func hash (s:String) -> Int {
var z = 19
let key = "abcdefghijk"
for var i = 0; i < s.characters.count; i++ {
let index = s.startIndex.advancedBy(i)
let char = s[index]
if let f = key.characters.indexOf(char) {
print(f) //This outputs the number I want to use in the next line, but as String.CharacterView.Index, not an Int
z = (z * f) //obviously this won't work
}
// So instead we try this:
z = z * s.startIndex.distanceTo(key.characters.indexOf(char)!))
// It works for the first few characters then I get "fatal error: can not increment endIndex" and a EXC_BAD_INSTRUCTION
}
return z
}
I'm struggling to use Swift String to find the index I want to use as an Int in some kind of a hash function. In case it isn't clear:
User inputs a string, the function iterates through each character, finding that character in the key and then takes the index of that character in key and multiplies it to the existing z counter.
I get the results I want but only in the wrong type which doesn't let me convert to Int. Anyone know how?
Thanks

f = key.characters.indexOf(char) is an index into the characters
of key, therefore you have to compute the distance to the start index of key, not s:
z = z * key.startIndex.distanceTo(key.characters.indexOf(char)!))
which you can move back to your if-let block:
if let f = key.characters.indexOf(char) {
z = z * key.startIndex.distanceTo(f)
}
You also might want to use the overflow operator &*
if let f = key.characters.indexOf(char) {
z = z &* key.startIndex.distanceTo(f)
}
otherwise the application will crash if the result of the
multiplication does not fit into an Int.
Generally, the indexes of a Swift String can only be used
with the same string (regardless of string length), as the following
example demonstrates:
let s1 = "abc"
let i1 = s1.characters.indexOf("b")!
print(i1) // 1
let s2 = "🇩🇪a🇩🇪b🇩🇪c"
print(s2.characters.count) // 6
let d2 = s2.startIndex.distanceTo(i1) // fatal error: can not increment endIndex

If you make your key into an array of Characters, then indexOf will return the Int you need:
func hash (s:String) -> Int {
var z = 19
let key = Array("abcdefghijk".characters)
for char in s.characters {
if let f = key.indexOf(char) {
print(f)
z = (z &* (f + 1))
}
}
return z
}
Also, if your character is the first index in the key you will get a value of 0 which will make your hash value 0, so I've added 1 to f. I also incorporated &* as suggested by #MartinR to prevent Int overflow.

First, don't use forced unwrap as you can end up easily crashing your app (as it seems it already happened).
Second, you already test for the validity of key.characters.indexOf(char), you can place the z computation within the if-let:
z = z * s.startIndex.distanceTo(f)
What happens with your code is that the hash() function crashes as soon as it encounters a character beyond k, so you should also add all possible characters to key.

Related

What is the error "A type instantiation involves a byref type." and what is a workaround in F#

I have some code wrapping TA-Lib and a lot of the wrappers are very similar:
let sma (timePeriod: int) (data: float[]) =
let mutable outStartIndex = 0
let mutable outNbElement = 0
let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = Core.Sma(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, smaData)
if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")
let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding smaData
let ema (timePeriod: int) (data: float[]) =
let mutable outStartIndex = 0
let mutable outNbElement = 0
let mutable emaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = Core.Ema(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, emaData)
if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")
let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding emaData
What I could like to do is create a generic function where I can just pass the TA-Lib function to call. Something like:
let myGenericFunction (timePeriod: int) (data: float[]) TALibFunc =
let mutable outStartIndex = 0
let mutable outNbElement = 0
let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = TALibFunc(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, smaData)
if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")
let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding smaData
but the error I am getting is:
[FS0412] A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
Is there a workaround for this? I am not familiar with this issue.
Short answer: replace your mutable parameters with ref.
TA-Lib has a very unfortunate API: those pesky out-parameters (known in F# as byref), they always make trouble. In this case, they cannot be part of a generic type instantiation.
Here's a much shorter example. Consider a good old list<T>. We can make an empty list<int>:
let noInts = [] : list<int>
But what if those ints are byref?
let noRefs = [] : list< byref<int> >
No can do - says the compiler. A type instantiation involves a byref type. This is not permitted by the rules of Common IL. Sorry.
In your case, the last parameter of myGenericFunction is an F# function. In F# functions are represented by the type FSharpFunc<T, R> (where T is argument and R is result). So the type of your last parameter is this:
FSharpFunc< int * int * float array * int * byref<int> * byref<int> * float array, int >
See those two byref<int>s in there? Those are &outStartIndex and &outNbElement. And they are forbidden in a generic instantiation. Tough luck.
But there is hope!
The mutable keyword is only one of two ways to make mutable cells in F#. The other way is ref:
let x = ref 0 // Initialization
printfn "%d" !x // Prints "0"
x := 42 // Mutation
printfn "%d" !x // Prints "42"
It's an old-school thing, predates mutable, is implemented as a library (as opposed to a language construct), and in most cases mutable is better. But this is not one of those cases!
It turns out that:
Unlike true .NET CIL out-parameters, ref cells can be part of generic instantiation just fine. Because, from .NET point of view, they're nothing special - just another class.
The F# compiler has special sauce for them: when the expected type is a ref, but you're trying to pass a function with an out-parameter in its place, the compiler will automatically generate some wrapping code for you.
So, armed with this knowledge, you can modify myGenericFunction like this:
let myGenericFunction (timePeriod: int) (data: float[]) TALibFunc =
let outStartIndex = ref 0
let outNbElement = ref 0
let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = TALibFunc(0, (data.Length - 1), data, timePeriod, outStartIndex, outNbElement, smaData)
...
And then the consumers can call it like this:
myGenericFunction 42 [|1; 2; 3|] Core.Sma // Wrapping code gets generated here

Ambiguous use of filter when getting frequency count of characters in a string

I implemented a function to calculate the hamming distance using Swift, it uses the xor operation x ^ y to get the different bits. Then, I convert the result from an Int to a String of 8 characters which is the 8 bit representation of my Xor. However, I am getting the error:
Compile Error: ambiguous use of 'filter'
class Solution {
func hammingDistance(_ x: Int, _ y: Int) -> Int {
let xor = x ^ y //xor: compares bits
let xorBinary = String(xor, radix: 2)
let xor8BitBinaryStr = String(repeating: Character("0"), count: 8 - xorBinary.count) + xorBinary
return xor8BitBinaryStr.filter({ $0 == "1" }).count
}
}
let c = Solution()
print(c.hammingDistance(1, 4)) //prints 2
You can filter like this to avoid confusion for the compiler,
let items = xor8BitBinaryStr.filter({ $0 == "1"})
return items.count
OR
return Array(xor8BitBinaryStr).filter({ $0 == "1" }).count
To solve this, declare the type of the xor8BitBinaryStr before you perform operations on it.
let xor8BitBinaryStr : `data type here` = String(repeating: Character("0"), count: 8 - xorBinary.count) + xorBinary
In Swift 4.0, there are two filter methods on String which only differ by their return type.
One returns String, the other [Character].
If you don't explicitly declare the type of the return you expect, it defaults to String.
Therefore, if you want to get [Character], you need to do something like this:
let chars: [Character] = xor8BitBinaryStr.filter({ $0 == "1" })
return chars.count
EDIT: This was a bug in Swift that was fixed, presumably in 4.1. It was marked Resolved on 11/17/17. See https://bugs.swift.org/browse/SR-5175?jql=text%20~%20%22filter%22

Error Handling in a Recursive Swift Function [duplicate]

I am making fuction that calculate factorial in swift. like this
func factorial(factorialNumber: UInt64) -> UInt64 {
if factorialNumber == 0 {
return 1
} else {
return factorialNumber * factorial(factorialNumber - 1)
}
}
let x = factorial(20)
this fuction can calculate untill 20.
I think factorial(21) value bigger than UINT64_MAX.
then How to calculate the 21! (21 factorial) in swift?
func factorial(_ n: Int) -> Double {
return (1...n).map(Double.init).reduce(1.0, *)
}
(1...n): We create an array of all the numbers that are involved in the operation (i.e: [1, 2, 3, ...]).
map(Double.init): We change from Int to Double because we can represent bigger numbers with Doubles than with Ints (https://en.wikipedia.org/wiki/Double-precision_floating-point_format). So, we now have the array of all the numbers that are involved in the operation as Doubles (i.e: [1.0, 2.0, 3.0, ...]).
reduce(1.0, *): We start multiplying 1.0 with the first element in the array (1.0*1.0 = 1.0), then the result of that with the next one (1.0*2.0 = 2.0), then the result of that with the next one (2.0*3.0 = 6.0), and so on.
Step 2 is to avoid the overflow issue.
Step 3 is to save us from explicitly defining a variable for keeping track of the partial results.
Unsigned 64 bit integer has a maximum value of 18,446,744,073,709,551,615. While 21! = 51,090,942,171,709,440,000. For this kind of case, you need a Big Integer type. I found a question about Big Integer in Swift. There's a library for Big Integer in that link.
BigInteger equivalent in Swift?
Did you think about using a double perhaps? Or NSDecimalNumber?
Also calling the same function recursively is really bad performance wise.
How about using a loop:
let value = number.intValue - 1
var product = NSDecimalNumber(value: number.intValue)
for i in (1...value).reversed() {
product = product.multiplying(by: NSDecimalNumber(value: i))
}
Here's a function that accepts any type that conforms to the Numeric protocol, which are all builtin number types.
func factorial<N: Numeric>(_ x: N) -> N {
x == 0 ? 1 : x * factorial(x - 1)
}
First we need to declare temp variable of type double so it can hold size of number.
Then we create a function that takes a parameter of type double.
Then we check, if the number equal 0 we can return or do nothing. We have an if condition so we can break the recursion of the function. Finally we return temp, which holds the factorial of given number.
var temp:Double = 1.0
func factorial(x:Double) -> Double{
if(x==0){
//do nothing
}else{
factorial(x: x-1)
temp *= x
}
return temp
}
factorial(x: 21.0)
I make function calculate factorial like this:
func factorialNumber( namber : Int ) -> Int {
var x = 1
for i in 1...namber {
x *= i
}
return x
}
print ( factorialNumber (namber : 5 ))
If you are willing to give up precision you can use a Double to roughly calculate factorials up to 170:
func factorial(_ n: Int) -> Double {
if n == 0 {
return 1
}
var a: Double = 1
for i in 1...n {
a *= Double(i)
}
return a
}
If not, use a big integer library.
func factoruial(_ num:Int) -> Int{
if num == 0 || num == 1{
return 1
}else{
return(num*factoruial(num - 1))
}
}
Using recursion to solve this problem:
func factorial(_ n: UInt) -> UInt {
return n < 2 ? 1 : n*factorial(n - 1)
}
func factorial(a: Int) -> Int {
return a == 1 ? a : a * factorial(a: a - 1)
}
print(factorial(a : 5))
print(factorial(a: 9))

Why would the F# compiler check if the newly created array is null?

I am playing around with F# and wanted to check how it generates code compared to C# and found a strange line.
I am using dotTrace to decompile code and make C# equivalent. I have also tried to check IL code using LinqPad.
My code is quite small.
open System
[<EntryPoint>]
let main argv =
let mutable sum = 0
// 1000 or 997
//let arr : int array = Array.zeroCreate 997
//let arr = Enumerable.Range(0, 997).ToArray()
let arr :int array = [|0..997|]
arr |> Array.iter (fun x -> sum <- sum + x)
printfn "%i" sum
0
And this is what I get.
{
int func = 0;
int[] numArray = SeqModule.ToArray<int>(Operators.CreateSequence<int>(Operators.OperatorIntrinsics.RangeInt32(0, 1, 997)));
if ((object) numArray == null)
throw new ArgumentNullException("array");
int length = numArray.Length;
int index = 0;
int num1 = length - 1;
if (num1 >= index)
{
do
{
int num2 = numArray[index];
func += num2;
++index;
}
while (index != num1 + 1);
}
PrintfModule.PrintFormatLineToTextWriter<FSharpFunc<int, Unit>>(Console.Out, (PrintfFormat<FSharpFunc<int, Unit>, TextWriter, Unit, Unit>) new PrintfFormat<FSharpFunc<int, Unit>, TextWriter, Unit, Unit, int>("%i")).Invoke(func);
return 0;
}
}
And this is how IL looks like.
// IL_0019: stloc.1 // 'numArray [Range(Instruction(IL_0019 stloc.1)-Instruction(IL_0040 ldloc.1))]'
// IL_001a: ldloc.1 // 'numArray [Range(Instruction(IL_0019 stloc.1)-Instruction(IL_0040 ldloc.1))]'
// IL_001b: box int32[]
// IL_0020: brfalse.s IL_0025
// IL_0022: nop
// IL_0023: br.s IL_0030
// IL_0025: ldstr "array"
// IL_002a: newobj instance void [mscorlib]System.ArgumentNullException::.ctor(string)
// IL_002f: throw
Compiled using Release, .Net 4.6, FSharp.Core 4.4.0.0, Optimize code, Generate Tail Calls.
I am very curious about the NULL check and cast.
(object) numArray == null
I do understand why the obj cast is done. The array is not a null and can't be checked without.
I am curious (don't thinks it is a problem) and the question is more about compiler.
Why would it be useful to check for null? I am not defining an option type.
Under what conditions the exception will fire.
That check is part of the implementation of Array.iter. The compiler just seems not to be smart enough to figure out that box arg in this case is never going to be null.

How to convert string array to float array and substitute Double.NaN for non-numeric values?

I'm writing a parser for CSV data, and am trying to determine how to handle records
that are blank ("") or contain character data ("C"). The parser code I have below works great, but forces me to deal with the float conversions later. I'd like to be able to just make my string[][] a float[][], and handle the conversions when I parse the file, but I notice that it blows up with any non-numeric data. Ideally there would be no non-numeric or blank values, but they are unavoidable, and as such, have to be dealt with.
Can someone possibly recommend a concise approach to attempt to convert to Double, and then if it doesn't work, replace with Double.NaN instead? (Without sacrificing much performance if possible). Thank you.
let stringLine = [| "2.0"; "", "C"|]
let stringLine2Float = Array.map float stringLine
//desiredFloatArray = [| 2.0; Double.NaN; Double.NaN |]
type csvData = { mutable RowNames: string[]; mutable ColNames: string[]; mutable Data: string[][] }
let csvParse (fileString: string) =
let colNames = ((fileLines fileString |> Seq.take 1 |> Seq.nth 0).Split(',')).[1..]
let lines = fileLines fileString |> Seq.skip 1 |> Array.ofSeq
let rowNames = Array.init lines.Length string;
let allData : string [][] = Array.zeroCreate rowNames.Length
for i in 0..rowNames.Length - 1 do
let fields = lines.[i].Split(',')
allData.[i] <- fields.[1..]
rowNames.[i] <- fields.[0]
{ RowNames = rowNames; ColNames = colNames; Data = allData }
Use this instead of the built-in float conversion:
let cvt s =
let (ok,f) = System.Double.TryParse(s)
if ok then f else nan

Resources