I have a simple question regarding the Minizinc's syntax. My input .dzn file contain a set of 2 dimentional arrays (approximately up to 30 arrays), declared as follows:
rates_index_0 = array2d(1..3, 1..501, [ 15, 20, 23, ....
rates_index_12 = array2d(1..3, 1..501, [ 21, 24, 27, ....
...
note: index numbers have gaps in them (e.g., 12 -> 20)
In my model, I need to use one of these arrays depending on the value of the variable. In common programming language I would solve it using a map or a dictionary datastructure. But in Minizinc I am hardcoding this in the following way:
function var int: get_rate(int: index, var int: load, int: dc_size) =
if index == 0 then
rates_index_0[dc_size, load]
else if index == 12 then
rates_index_12[dc_size, load]
else if index == 16 then
rates_index_16[dc_size, load]
else if index == 20 then
rates_index_20[dc_size, load]
else
assert(false, "unknown index", 0)
endif endif endif endif;
The one obvious problem with this code is that I need to change model each time I change input. Is there a better way how I can code this in a generic way?
Thanks!
In an more abstract way a map-structure is nothing more than a function mapping inputs of a certain type to an array. A map can thus be replaced by a array and a function. (The difference being you will have to define the function yourself)
Before I get started with the rest I would like to point out that if your model compiles generally fast, you might want to try a triple array without the function, rates_index = array3d(0..60, 1..3, 1..501, [ 15, 20, 23, ..... This will cost more memory, but will make the model more flexible.
The general way of using a map-structure would be to define a function map_index, that maps your input, in this case integers, to the index of the array, also integers. This means that we can then define a extra level array to point to the right one: rates_index = array3d(0..nr_arrays, 1..3, 1..501, ..... This means that the content of get_rates can then be: rates_index[map_index(index), dc_size, load].
The function map_index itself in its simplest form would contain another version of your if-then-else statements:
function int: map_index(int: index) =
if index == 0 then
0
else if index == 12 then
1
else if index == 16 then
2
else if index == 20 then
3
else
assert(false, "unknown index", 0)
endif endif endif endif;
However you can make it dynamic by generating an extra array containing the array number for each index, putting -1 for all arrays that are not available. For your example the mapping would look like this: array[0..20] of int: mapping = [0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 2, -1, -1, -1, 3];. The map_index function could then dynamically be defined as:
function int: map_index(int: index) =
mapping[index];
Related
How to put the same, but positive, before each negative element of the array. Count the number of inserted elements
example:
var arrayInt: [Int] = [22, 16, -39, 1, -200]
result: [22, 16, 39, -39, 1, 200, -200]
what to use for-in or method .map or method .filter
Thanks for the help!
Here's a relatively simple implementation:
let result: [Int] = arrayInt.reduce(into: []) { acc, item in
if item < 0 {
acc.append(-item)
}
acc.append(item)
}
reduce allows you to transform an array into an arbitrary type. In this case, you still want an [Int], but you don't want to be constrained to the same number of elements (like map would do).
If you need the number of inserted elements:
let inserted = result.count - arrayInt.count
Note that you could also build this into the result by returning a tuple with a count instead of just an [Int]
Keep in mind this is not the only possible solution -- just a relatively straightforward one.
In response to the comments, you could also turn this into a one-liner with something like flatMap: arrayInt.flatMap { $0 < 0 ? [-$0, $0] : [$0] }
In Swift, is it possible to enumerate a sequence starting at 1?
In my case, I'm using the SQLite C interface to bind values to prepared statements. The second argument of the sqlite3_bind_*() routines is the index of the SQL parameter to be set. The indices start at 1. (Ie, they're one-based.)
I could use Sequence.enumerated() and just add 1 to n inside each iteration, like so:
for (n, value) in values.enumerated() {
sqlite3_bind_int(stmt, Int32(n)+1, value)
}
But is there a way to start n from 1?
No, all collections indices in Swift are zero based but if you really want you can create your own custom enumeration zipping a range of Int32 values and the source collection:
extension Collection {
var enumerated: Zip2Sequence<PartialRangeFrom<Int32>, Self> { zip(1..., self) }
}
usage:
let values: [Int32] = [10, 20, 30]
for (n, value) in values.enumerated {
print("value:", value, "at:", n)
}
This will print
value: 10 at: 1
value: 20 at: 2
value: 30 at: 3
As others have said, array indexes start at 0 in Swift, so if you want to have 1-based indexes out of the box, you'll need to write some extra code.
If you're only using the index once then any workarounds might not worth the effort, and the incrementing at the call site is the most straightforward solution.
If however you will need to use the incremented index multiple times within the loop, another approach you could take would be to shadow the index:
for (n, element) in [1, 2,3].enumerated() {
let n = n + 1
sqlite3_bind_int(stmt, Int32(n), value)
}
Another approach could be using map():
for (n, element) in [1, 2,3].enumerated().map({($0+1,$1)}) {
sqlite3_bind_int(stmt, Int32(n), value)
}
, however not sure if you gain much with this solution, as the code is a little bit obscure.
I have an app with a 6x7 grid that lets the user input values. After each value is obtained the app checks to find if any of the consecutive values create a sum of ten and executes further code (which I have working well for the 4 test cases I've written). So far I've been writing if statements similar to the below:
func findTens() {
if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue + rowOneColumnFourPlaceHolderValue) == 10 {
//code to execute
} else if (rowOneColumnOnePlaceHolderValue + rowOneColumnTwoPlaceHolderValue + rowOneColumnThreePlaceHolderValue + rowOneColumnFourPlaceHolderValue + rowOneColumnFivePlaceHolderValue) == 10 {
//code to execute
}
That's not quite halfway through row one, and it will end up being a very large set of if statements (231 if I'm calculating correctly, since a single 7 column row would be 1,2-1,2,3-...-2,3-2,3,4-...-67 so 21 possibilities per row). I think there must be a more concise way of doing it but I've struggled to find something better.
I've thought about using an array of each of the rowXColumnYPlaceHolderValue variables similar to the below:
let rowOnePlaceHolderArray = [rowOneColumnOnePlaceHolderValue, rowOneColumnTwoPlaceHolderValue, rowOneColumnThreePlaceHolderValue, rowOneColumnFourPlaceHolderValue, rowOneColumnFivePlaceHolderValue, rowOneColumnSixPlaceHolderValue, rowOneColumnSevenPlaceHolderValue]
for row in rowOnePlaceHolderArray {
//compare each element of the array here, 126 comparisons
}
But I'm struggling to find a next step to that approach, in addition to the fact that those array elements then apparently because copies and not references to the original array anymore...
I've been lucky enough to find some fairly clever solutions to some of the other issues I've come across for the app, but this one has given me trouble for about a week now so I wanted to ask for help to see what ideas I might be missing. It's possible that there will not be another approach that is significantly better than the 231 if statement approach, which will be ok. Thank you in advance!
Here's an idea (off the top of my head; I have not bothered to optimize). I'll assume that your goal is:
Given an array of Int, find the first consecutive elements that sum to a given Int total.
Your use of "10" as a target total is just a special case of that.
So I'll look for consecutive elements that sum to a given total, and if I find them, I'll return their range within the original array. If I don't find any, I'll return nil.
Here we go:
extension Array where Element == Int {
func rangeOfSum(_ sum: Int) -> Range<Int>? {
newstart:
for start in 0..<count-1 {
let slice = dropFirst(start)
for n in 2...slice.count {
let total = slice.prefix(n).reduce(0,+)
if total == sum {
return start..<(start+n)
}
if total > sum {
continue newstart
}
if n == slice.count && total < sum {
return nil
}
}
}
return nil
}
}
Examples:
[1, 8, 6, 2, 8, 4].rangeOfSum(10) // 3..<5, i.e. 2,8
[1, 8, 1, 2, 8, 4].rangeOfSum(10) // 0..<3, i.e. 1,8,1
[1, 8, 3, 2, 9, 4].rangeOfSum(10) // nil
Okay, so now that we've got that, extracting each possible row or column from the grid (or whatever the purpose of the game is) is left as an exercise for the reader. 🙂
I tried to remove an element in NSUserDefaults which is the same as stockSymbol's value when click a button. My idea is that cast the NSUserDefaults to an array and remove the element with removeAtIndex. Here is my code.
#IBAction func buttonFilledStarClicked(sender: AnyObject) {
NSLog("Filled star clicked")
self.buttonFilledStar.hidden = true
self.buttonEmptyStar.hidden = false
var Array = NSUserDefaults.standardUserDefaults().objectForKey("favorites")! as! [String]
var countArray = (NSUserDefaults.standardUserDefaults().objectForKey("favorites")! as! [String]).count - 1
for i in 0...countArray {
if stockSymbol! == Array[i] {
NSLog("i is : \(i)")
Array.removeAtIndex(i)
}
else {}
}
NSLog("Array is: \(Array), countArray is: \(countArray)")
}
However it has 'out of index' error.
It works when I just comment Array.removeAtIndex(i) out.
Array looks like this --
["aa", "bb", "Test!", "Test!"]
Any suggestions? Thank you in advance.
So, the change you can make to resolve the error with the least impact on your code overall would be to simply iterate through the indices backwards:
for i in (0...countArray).reverse() {
if stockSymbol! == Array[i] {
NSLog("i is : \(i)")
Array.removeAtIndex(i)
}
else {}
}
But the best option is to just use Swift's filter:
Array = Array.filter { $0 != stockSymbol }
An expanded note on why the crash is happening...
Let's take a simplified example. Say I have the following array:
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
And I want to remove all of the odd numbers out of it. Using your first naïve approach, I might write my logic like this:
for i in 0..<arr.count {
if arr[i] % 2 != 0 {
arr.removeAtIndex(i)
}
}
Look at what happens on each iteration.
On the first iteration, we have arr[i] of 1. This is an odd number, so we'll removeAtIndex, and our array now actually looks like this:
[2, 3, 4, 5, 6, 7, 8, 9, 10]
The array's size is now smaller--it has just 9 elements. But the loop doesn't work like an old C-style for loop where i < arr.count is checked on each iteration (which is part of why this loop is faster).
But notice something else that happens when we iterate forward...
On the second iteration, i is equal to 1, and so what does arr[i] give us? It gives us 3. We never even check 2. On the first iteration, when i was 0, it was at index 1. On the second iteration, when i is 1, the 2 is at index 0.
So on the second iteration, we'll call removeAtIndex with i equal to 1 and remove the 3.
This pattern will continue for a few iterations until we end up with our array of just even numbers:
[2, 4, 6, 8, 10]
But this happens after the iteration where i was equal to 4, and the loop is going to try running until i is equal to 10.
On the sixth iteration of the loop, we try to access the element at index 5 of the array. But the array only has five elements, so the largest index is 4. When we try to access index 5, we crash.
You should not remove it from inside of the loop, when you call removeAtIndex(i) Array removes the item so you have 1 less item then countArray.. so you have to have another array to remember which item you want to remove and remove it outside of the loop.. or better option is to use filter
// Filter only strings that match stockSymbol
Array = Array.filter { $0 == stockSymbol! }
Try to find out which i that give you index out of range result. Is it the 0 or the last one. Maybe you will find some other useful clue.
First of all Array is a type, maybe you can call:
var favourites = NSUserDefaults.standardUserDefaults().objectForKey("favorites")! as! [String]
Then you don't need a array's count variable you can access using count arrays property.
Finally if you are iterating through an array and remove an element it always going to throw "index's error" because the index is not the same as the beginning..
For solving this you can take two pointers of the index variable, but what I would do is something like this:
var correctElements = favourites.filter({$0!=stockSymbol})
Here is the requirement: the input is a number which will divide an image into several equal part. For example, if the input is 4, it will return 3 parts: the values are the imgSize/4 imgSize/4 * 2 and imgSize/4 * 3.
If the input is n, then it will return n - 1 elements, as in the following implementation:
if (colorLevel == 8)
divide_thres = [ round(imgSize/8) round(imgSize/8)*2 round(imgSize/8)*3 round(imgSize/8)*4
round(imgSize/8)*5 round(imgSize/8)*6 round(imgSize/8)*7 ];
elseif (colorLevel == 4)
divide_thres = [ round(imgSize/4) round(imgSize/4)*2 round(imgSize/4)*3 ];
elseif (colorLevel == 3)
divide_thres = [ round(imgSize/3) round(imgSize/3)*2 ];
end
I want to allow the user to input a value between 2 and 255, and then automatically generate the divide_thres corresponding to that input. How can I re-write this code to be more efficient?
There are several problems with your code:
In each case, you unnecessarily divide imgSize by the same factor multiple times (instead of just once and for all).
You perform many "manual" scalar multiplications, but you could simply multiply the scalar value by a vector generated by the range 1 : colorLevel - 1.
Because the length of the resulting divide_thres vector can be easily computed from the value of colorLevel, there is no need to treat each case separately in an if statement.
Moreover, even if you had to compute the length in a different manner for the cases imgSize = 3, 4, and 8, you would be better off using a switch statement instead of an if statement, because the former would save you the trouble of writing imgSize == ... each time, which is prone to errors and a form of code duplication.
Here's a much simplified approach:
if 2 <= colorLevel && colorLevel <= 255
divide_thres = round(imgSize / colorLevel) * (1 : colorLevel - 1);
else
error('invalid colorLevel value') % (or some other informative message)
end
This should do it -
divide_thres = [1:colorLevel-1]*round(imgSize/colorLevel)