How to fix C-style for statement has been removed in Swift 3? - ios

I am converting old Swift 2 code to Swift 3 and I am facing difficulty in converting following for loop
for (var nSize = merkleTree.count; nSize > 1; nSize = (nSize + 1) / 2)
{
//...
}
There are many similar question on SO but I didn't find any solution applicable to my problem Or I didn't understand.
I thought that below code will work but it is giving error.
for var nSize in merkleTree.count.stride(to:1, by:(nSize+1)/2)
Use of unresolved identifier 'nSize'

I don't think this can be written using for anymore, but you can use while loop to get the job done:
var nSize = merkleTree.count
while nSize > 1 {
// loop body
nSize = (nSize + 1) / 2
}
I would expect stride not to work in this case, because as your error states, you cannot use nSize as the stride parameter - nSize is iterating variable that gets declared based on the range, so you need the range to exist. At least that's my interpretation of the error (I know that theoretically you can generate range based on the previously generated item, but obviously stride does not work that way).
I believe you can find a way to generate a proper array of values using reduce (because I was able to, see below, maybe you can make it simpler), or by implementing your own stride that would accept a closure instead of a step (which would allow you to compute next item based on previous one), but both approaches are more complicated and obscure than using the simple while loop, so I personally prefer the while loop.
My not so nice reduce implementation (in result it uses an array and not a range, since by looking at NSRange I don't think you can create a range that does not step by 1):
let merkleTree = [1,2,3,4,5,6,7,8,9]
let numberOfDivisions = Int(log2(Double(merkleTree.count))) + 1
let startValue = merkleTree.count
let nSizes = (0..<numberOfDivisions).reduce([startValue]) { (result, next) -> [Int] in
var newResult = result
newResult.append((result.last! + 1) / 2)
return newResult
}
print(nSizes)
// and now you can for-in it:
for nSize in nSizes {
// ...
}

Related

Mapping Structs in Swift

I have an array of a custom struct that has a INT variable that I would like to get the sum of conditionally based on another variable of the struct. Here is example of what the code looks like:
struct Point {
var amount: Int
var add: Bool
}
let arr = [Point(amount: 9, add: false), Point(amount: 9, add: true), Point(amount: 9, add: true)]
let sum:Int = arr.compactMap({ point in
return point.add ? point.amount : 0
})
print(sum)
But I am getting this error: error: cannot convert value of type '[Int]' to specified type 'Int'
Isn't compact map supposed to reduce the array down to a certain type? How can I accomplish what I am trying to do?
You are looking for reduce, not compactMap. reduce takes an array and transforms it to a single value.
What you're looking for could done like this:
let sum: Int = arr.reduce(0, { acc, point in
acc + (point.add ? point.amount : 0)
})
Or, turned into a one-liner:
let sum:Int = arr.filter(\.add).map(\.amount).reduce(0, +)
The second solution is not particularly efficient -- not suitable for larger collections, but perfectly reasonable for your example. Unless things have changed, even the first solution won't win any speed tests against a simple for loop. But, again, unless you have huge collections you're working with, it's perfectly reasonable.

Can't understand the logic of F# mutable variable inside function body

I'm learning F# and get stuck with the concept of mutable keyword.
Please see the below example:
let count =
let mutable a = 1
fun () -> a <- a + 1; a
val count: unit -> int
Which increases by 1 every time it's called with (). But next code does not:
let count =
let mutable a = 1
a <- a + 1
a
val count: int
Which is always 2.
In the book I'm studying with, it says with the first example, "The initialization of mutable value a is done only once, when the function has called first time."
When I started learning FP with haskell, the way it handled side effects like this totally burnt my brain, but F# mutable is destroying my brain again, with a different way. What's the difference between above two snippets? And, what's the true meaning and condition of above sentence, about the initialization of mutable value?
Your second example
let count =
let mutable a = 1
a <- a + 1
a
Defines a mutable variable initialised to 1, then assigns a new value (a + 1) to it using the <- operator before returning the updated value on the last line. Since a has type int and this is returned from the function the return type of the function is also int.
The first example
let count =
let mutable a = 1
fun () -> a <- a + 1; a
also declares an int a initialised to 1. However instead of returning it directly it returns a function which closes over a. Each time this function is called, a is incremented and the updated value returned. It could be equivalently written as:
let count =
let mutable a = 1
let update () =
a <- a + 1
a
update
fun () -> ... defines a lambda expression. This version returns a 1-argument function reflected in the different return type of unit -> int.
The first example of count initializes a mutable variable, and returns a closure around this variable. Every time you call that closure, the variable is increased, and its new value returned.
The second example of count is just an initialization block that sets the variable, increases it once, and returns its value. Referring to count again only returns the already computed value again.

How to edit function input in Swift?

I am building an idle clicker app in Swift and I am adding in auto clicks through a function. I want to be able to enter the price through the input for the function, but because the input is a constant, I can't add to the cost price by 9% like I want every time the user clicks the upgrade.
For example if I type 50.0 into the initialPrice how would I make it so that it increases by 10% every time the user clicks it.
func upgrade(intialPrice : Float) {
var upgradePrice = intialPrice
AutoClicks += 1
totalClicks = totalClicks - Int(upgradePrice)
upgradePrice = upgradePrice + (upgradePrice * 0.1)
burritoLvl1Label.text = ("$" + "\(Int(upgradePrice))")
}
I am very new to coding so if you see any way I could make this shorter that would be very helpful.
The other answers have suggested using an inout parameter, and while this will work, it is not a pattern I would recommend. Generally it is better to avoid "side effects" in functions and use inout only when there is a very good reason.
The more general approach would be to have a function that returns the new value.
You might also want to consider using a Decimal rather than a Float when dealing with currency.
Similarly, updating the label probably shouldn't be in this function
func upgrade(initialPrice : Decimal) -> Decimal {
autoClicks += 1
totalClicks -= Int(truncating: initialPrice as NSDecimalNumber)
return initialPrice * 1.1
}
You can then call this function like so:
price = upgrade(initialPrice: price)
burritoLvl1Label.text = ("$" + "\(Int(truncating:price as NSDecimal))")
You need to pass the value in as an inout argument to be able to mutate it. You can also make your implementation more concise by using the compound assignment operators, +=, -= and *=. You should also make sure that you conform to the Swift naming convention, which is loweCamelCase for function and variable names (autoClicks) and UpperCamelCase for types.
func upgrade(initialPrice: inout Float) {
autoClicks += 1
totalClicks -= Int(upgradePrice)
upgradePrice *= 1.1
burritoLvl1Label.text = ("$" + "\(Int(upgradePrice))")
}
However, you should be aware that in most cases you should return the mutated value from a function instead of mutating it by passing it in as an inout parameter. It is especially bad practice to mutate some instance variables of your class without passing them into the function explicitly, while modifying some others using an inout argument.
You should make your input parameter as inout.
More info about swift functions.
func upgrade(intialPrice: inout Float) {
var upgradePrice = intialPrice
AutoClicks += 1
totalClicks = totalClicks - Int(upgradePrice)
upgradePrice = upgradePrice + (upgradePrice * 0.1)
burritoLvl1Label.text = ("$" + "\(Int(upgradePrice))")
}
Hope it helps!

Swift String from imported unsigned char 2D array

I am using a 3rd party C library in my iOS application, which I am in the process of converting from Objective-C to Swift. I hit an obstacle when attempting to read one of the structs returned by the C library in Swift.
The struct looks similar to this:
typedef unsigned int LibUint;
typedef unsigned char LibUint8;
typedef struct RequestConfiguration_ {
LibUint8 names[30][128];
LibUint numberNames;
LibUint currentName;
} RequestConfiguration;
Which is imported into Swift as a Tuple containing 30 Tuples of 128 LibUint8 values. After a long time of trial and error using nested withUnsafePointer calls, I eventually began searching for solutions to iterating a Tuple in Swift.
What I ended up using is the following functions:
/**
* Perform iterator on every children of the type using reflection
*/
func iterateChildren<T>(reflectable: T, #noescape iterator: (String?, Any) -> Void) {
let mirror = Mirror(reflecting: reflectable)
for i in mirror.children {
iterator(i.label, i.value)
}
}
/**
* Returns a String containing the characters within the Tuple
*/
func libUint8TupleToString<T>(tuple: T) -> String {
var result = [CChar]()
let mirror = Mirror(reflecting: tuple)
for child in mirror.children {
let char = CChar(child.value as! LibUint8)
result.append(char)
// Null reached, skip the rest.
if char == 0 {
break;
}
}
// Always null terminate; faster than checking if last is null.
result.append(CChar(0))
return String.fromCString(result) ?? ""
}
/**
* Returns an array of Strings by decoding characters within the Tuple
*/
func libUint8StringsInTuple<T>(tuple: T, length: Int = 0) -> [String] {
var idx = 0
var strings = [String]()
iterateChildren(tuple) { (label, value) in
guard length > 0 && idx < length else { return }
let str = libUint8TupleToString(value)
strings.append(str)
idx++
}
return strings
}
Usage
func handleConfiguration(config: RequestConfiguration) {
// Declaration types are added for clarity
let names: [String] = libUint8StringsInTuple(config.names, config.numberNames)
let currentName: String = names[config.currentName]
}
My solution uses reflection to iterate the first Tuple, and reflection to iterate the second, because I was getting incorrect strings when using withUnsafePointer for the nested Tuples, which I assume is due to signage. Surely there must be a way to read the C strings in the array, using an UnsafePointer alike withUsafePointer(&struct.cstring) { String.fromCString(UnsafePointer($0)) }.
To be clear, I'm looking for the fastest way to read these C strings in Swift, even if that involves using Reflection.
Here is a possible solution:
func handleConfiguration(var config: RequestConfiguration) {
let numStrings = Int(config.numberNames)
let lenStrings = sizeofValue(config.names.0)
let names = (0 ..< numStrings).map { idx in
withUnsafePointer(&config.names) {
String.fromCString(UnsafePointer<CChar>($0) + idx * lenStrings) ?? ""
}
}
let currentName = names[Int(config.currentName)]
print(names, currentName)
}
It uses the fact that
LibUint8 names[30][128];
are 30*128 contiguous bytes in memory. withUnsafePointer(&config.names)
calls the closure with $0 as a pointer to the start of that
memory location, and
UnsafePointer<CChar>($0) + idx * lenStrings
is a pointer to the start of the idx-th subarray. The above code requires
that each subarray contains a NUL-terminated UTF-8 string.
The solution suggested by Martin R looks good to me and, as far as I can see from my limited testing, does work. However, as Martin pointed out, it requires that the strings be NUL-terminated UTF-8. Here are two more possible approaches. These follow the principle of handling the complexity of C data structures in C instead of dealing with it in Swift. Which of these approaches you choose depends on what specifically you are doing with RequestConfiguration in your app. If you are not comfortable programming in C, then a pure Swift approach, like the one suggested by Martin, might be a better choice.
For the purposes of this discussion, we will assume that the 3rd party C library has the following function for retrieving RequestConfiguration:
const RequestConfiguration * getConfig();
Approach 1: Make the RequestConfiguration object available to your Swift code, but extract names from it using the following C helper function:
const unsigned char * getNameFromConfig(const RequestConfiguration * rc, unsigned int nameIdx)
{
return rc->names[nameIdx];
}
Both this function's signature and the RequestConfiguration type must be available to the Swift code via the bridging header. You can then do something like this in Swift:
var cfg : UnsafePointer<RequestConfiguration> = getConfig()
if let s = String.fromCString(UnsafePointer<CChar>(getNameFromConfig(cfg, cfg.memory.currentName)))
{
print(s)
}
This approach is nice if you need the RequestConfiguration object available to Swift in order to check the number of names in multiple places, for example.
Approach 2: You just need to be able to get the name at a given position. In this case the RequestConfiguration type does not even need to be visible to Swift. You can write a helper C function like this:
const unsigned char * getNameFromConfig1(unsigned int idx)
{
const RequestConfiguration * p = getConfig();
return p->names[idx];
}
and use it in Swift as follows:
if let s = String.fromCString(UnsafePointer<CChar>(getNameFromConfig1(2)))
{
print(s)
}
This will print the name at position 2 (counting from 0). Of course, with this approach you might also want to have C helpers that return the count of names as well as the current name index.
Again, with these 2 approaches it is assumed the strings are NUL-terminated UTF-8. There are other approaches possible, these are just examples.
Also please note that the above assumes that you access RequestConfiguration as read-only. If you also want to modify it and make the changes visible to the 3rd party library C code, then it's a different ballgame.

Fastest way to check Map for duplicate values?

Given a Map, assignment, what is the fastest way to check if it contains any duplicate values in Dart? I am currently using a Set formed from the Map's values and checking its length against the original Map, which works of course, but I'm wondering if there's an especially performant alternative.
Set d = new Set.from(assignment.values);
if (d.length < assignment.length) {
return false; // indicates has duplicates in this context
}
EDIT:
Tried #mezoni's solution modified for my program, but it actually ran a bit slower than my original version. It probably has more to do with constant times than anything else.
List values = new List.from(assignment.values);
Set set = new Set();
for (var i = 0; i < assignment.length; i++) {
if (!set.add(values[i])) {
return false;
}
}
Complexity wise you won't be able to get anything faster. Creating the Set and filling it with the values of the Map is linear in the number of elements. Clearly you have to run through all the values, so you can't do any better than that.
Maybe you could find a solution with a smaller constant factor, but that's not clear. In particular for larger sets I think the Set solution is pretty efficient.
This is more of a algorithms question than a Dart question. In any case, you have to check every value against the others, giving n-1 + n-2 + ... + n-(n-1) checks, or n^2/2. Programmatically, it's easy to create a set, but you could also generate an array, sort the array, and then iterate once to check for duplicates. That finishes in O(n log n).
Fastets way (if you realy need better performance):
void main() {
// Values from map
var values = [1,2,3,2,1,3,2,1];
var length = values.length;
var set = new Set();
var duplicate = false;
// Only for statistics purpose
var statistics = 0;
for(var i = 0; i < length; i++) {
statistics++;
if(!set.add(values[i])) {
duplicate = true;
break;
}
}
print("Duplicate: $duplicate");
print("Performed in ${statistics} iteration(s) from $length possible");
}
Output:
Duplicate: true
Performed in 4 iteration(s) from 8 possible
P.S.
The first example can be recommended to use with List values.
But because Map.values not a List but Iterable then it would be more efficient do not convert them to List but use as is.
Here is modified sample for use with Iterable objects.
It will be work faster because in this algorithm not required convert all values to the List object because it not want using of all elements without exception.
Instead it wants use as less as possible access operation on original source. If the source supports lazy operation of the access to values (as Iterable) this will be even better.
void main() {
// Values from map
var values = [1,2,3,2,1,3,2,1];
var assignment = {};
var length = values.length;
var key = 0;
for(var value in values) {
assignment[key++] = value;
}
var set = new Set();
var duplicate = false;
// Only for statistics purpose
var statistics = 0;
for(var value in assignment.values) {
statistics++;
if(!set.add(value)) {
duplicate = true;
break;
}
}
print("Duplicate: $duplicate");
print("Performed in ${statistics} iteration(s) from $length possible");
}

Resources