Swift algorithm to enumerate a multilinear map, using multiples indexes:[Int] - arrays

A multilinear map M has its elements stored in a one-dimension array of length N, with a Shape S defined by S:[Int] = [p,q,r,...] so that q*p*r*... = N. The Shape is of variable size, not known at compile time.
The issue I'm trying to solve is a generic approach to accessing the map's elements using an array of integers, which individual values are coordinates in the Shape S, ex: M[1,3,2], M[2,3,3,3] etc... This is a problem different from a simple enumeration of the map's elements.
One method is to use M[i,j,k] and implement a subscript method. Unfortunately, this approach hardcodes the map's shape, and the algorithm is no longer generic.
Say there's a utility function that returns an element index from a tuple derived from the map's Shape, so that:
func index(_ indexes:[Int]) -> Int {....}
func elementAt(indexes:[Int]) -> Element {
return elements_of_the_map[self.index(indexes)]
}
M.elementAt(indexes:[i,j,k]) or M.elementAt(indexes:[i,j,k,l,m]) always work. So the problem at this point is to build the array [i,j,k,...]
Question: Is there an algorithm to efficiently enumerate those indexes? Nested loops won't work since the number of loops isn't known at compile time, and recursive function seem to add a lot of complexity (in particular keeping track of previous indexes).
I'm thinking about an algorithm 'a la' base-x counting, that is adding one unit to the top right index, and moving leftwards one unit if the count exceeds the number of elements by the map's Shape.

Same idea, but less code:
func addOneUnit(shape: [Int], indexes: [Int]) -> [Int]? {
var next = indexes
for i in shape.indices.reversed() {
next[i] += 1
if next[i] < shape[i] {
return next
}
next[i] = 0
}
return nil
}

Here's the code, it's primitive, but should work. The idea is to increment, right-to-left, to move say to [1,2,2] from [1,2,1] with the shape constraint [2,3,3].
func add_one_unit(shape:[Int],indexes:[Int]) -> [Int]? {
//Addition is right to left, so we have to reverse the arrays. Shape Arrays are usually very small, so it's fast.
let uu = Array(indexes.reversed()); //Array to add one index to.
let shape_reversed = Array(shape.dimensions.reversed()); //Shape array.
var vv:[Int] = [];
var move_next:Bool = true;
for i in 0..<uu.count {
if move_next {
if uu[i] < shape_reversed[i] - 1 { //Shape constraint is OK.
vv.append(uu[i] + 1)
move_next = false;
} else {
vv.append(0) //Shape constraint is reached.
move_next = true;//we'll flip the next index.
}
} else {
vv.append(uu[i]) //Nothing to change.
}
}
return ( vv.reduce(true, { $0&&($1 == 0) }) ) ? nil : Array(vv.reversed()); //Returns nil once we reached the Zero Vector.
}
Which gives
add_one_unit(shape:[2,3,3],indexes:[0,0,0]) -> [0,0,1]
add_one_unit(shape:[2,3,3],indexes:[1,2,2]) -> [0,0,0]/nil
Once this is done, this function can be used to enumerate a multilinear map of any shape (a mapping of [i,j,k,...] to a unique index such as matrix to index mapping is necessary and depends on your implementation), or slice a map starting from any particular vector.

Related

Index out of range (fatal error) when summing diagonals in square arrays

I need difference between first and second diagonal in square matrix array
func diagonalDifference(arr: [[Int]]) -> Int {
var sumFirstDiag = 0
for i in 0...arr.count-1 {
sumFirstDiag = sumFirstDiag + Int(arr[i][i])
}
var sumSecondDiag = 0
for y in 0...arr.count-1 {
sumSecondDiag = sumSecondDiag + Int(arr[y][arr.count - y])
}
print(abs(sumFirstDiag - sumSecondDiag))
return abs(sumFirstDiag - sumSecondDiag)
}
let array = [
[1,2,3,11],
[4,5,6,12],
[7,8,9,90],
[1,3,5,7]]
diagonalDifference(arr: array)
Error message:
Fatal error: Index out of range: file Swift/ContiguousArrayBuffer.swift, line 444
I figured I'd share a more functional approach to this same problem:
// The sum of elements along the diagonal from top-left to bottom-right
func diagonal1Sum(_ input: [[Int]]) -> Int {
input.indices
.map { input[$0][$0] }
.reduce(0, +) // I wish Swift had a built-in `.sum` :(
}
// The sum of elements along the diagonal from top-right to bottom-left
func diagonal2Sum(_ input: [[Int]]) -> Int {
zip(input.indices, input.indices.reversed())
.map { input[$0][$1] }
.reduce(0, +)
}
// The absolute value of the difference in sums of the two diagonals.
func diagonalDifference(_ input: [[Int]]) -> Int {
abs(diagonal1Sum(input) - diagonal2Sum(input))
}
let array = [
[1,2,3,11],
[4,5,6,12],
[7,8,9,90],
[1,3,5,7],
]
print(diagonalDifference(array))
There's a few things to notice:
0...arr.count-1 should be just expressed as arr.indices. The first form crashes on empty arrays. See https://github.com/amomchilov/Blog/blob/master/Proper%20Array%20Iteration.md
arr[i][i] is already an Int, there's no need to convert that into an Int.
sumSecondDiag = sumSecondDiag + something is more simply written as just sumSecondDiag += something
Meaningless parameter names like arr shouldn't be keyword labels. Compare diagonalDifference(arr: array) and diagonalDifference(array). The arr: in the first form doesn't really give you any information you didn't already have. You should omit that keyword label using a _.
You should not print the result out of a function that computes a result like this. Return the result, then print it. This gives users of your function the ability to choose whether they want to print, or not.
And most importantly: you can iterate through arr.indices.reversed() to get a sequence of indices that go from high to low, allowing you to access the row elements from top right to bottom left.
This is the key to avoiding the bug you encountered. You forgot the crucial - 1, which is why you were accessing the index out of bounds and causing the crash. If you just use the reversed reverse the array first, then access the nth element, you'll get back the n-th last value, without needing to remember to do acc.count - n - 1.
To pick the row, you still need the regular "forward indices", like array.indices().
You can use zip(_:_:) to iterate both of them at the same time, using the "forward index" to select the row, and the "backward index" to select a particular number from that row.
Thanks to #Rob for this suggestion.
Update notes
I revamped my recommendation. I was previously suggesting to use input[$0].reversed()[$0] under the misunderstanding that the result of reversed would be a view onto the array that would just perform constant-time index arithmetic. This is not the case. Each of these reversed calls was doing a full linear reversal of the array.

iOS How to Find Minimum Difference Between the values of Array of Floating/Integer Values

I have an array of floating values:
let array:[Double] = [2270.87, 2285.15, 2273.49, 2312.89, 2323.07, 2336.14, 2355.09, 2633.0, 2671.34]
I need and single line logic using swift higher-order functions or array extension to find the minimum difference value from all differences between the values.
I tried but I'm unable to move further:
let array = [2270.87, 2285.15, 2273.49, 2312.89, 2323.07, 2336.14, 2355.09, 2633.0, 2671.34]
let minDiff = array.map( { *All differences between array of values* } ).reduce(0, min)
Actually I am showing these values in a graph. So I want the minimum absolute fluctuation between the values. in the above example like 2323.07 and 2336.14 have minimum fluctuation 10.18.
You can zip two arrays where second one doesn't have first element. Then you can get abs value of subtraction value with index x + 1 from that with index x, and using map() you can get the minimum value from all of those absolute values.
zip(array, array.dropFirst()).map { abs($1 - $0) }.min() // 10.180000000000291
If you want to find the minimum absolute difference between two consecutive elements of your array, you can use below extension, which maps over the indices of the array, to access 2 consecutive elements at a time.
dropLast is important to ensure that we stop iteration before the last element (since we calculate the diff between the penultimate and last element before reaching the last index).
extension Array where Element: Comparable, Element: SignedNumeric {
func minConsecutiveDiff() -> Element? {
indices.dropLast().map { abs(self[$0] - self[$0+1])}.min()
}
}
let array:[Double] = [2270.87, 2285.15, 2273.49, 2312.89, 2323.07, 2336.14, 2355.09, 2633.0, 2671.34]
array.minConsecutiveDiff() // 10.18
If you were interested in the diff between any two elements of the array, not just consecutive ones, you could get that by first sorting the Array and then calculating the diff between the consecutive elements of the sorted array as #MartinR pointed out in comments.
extension Array where Element: Comparable, Element: SignedNumeric {
func minDiff() -> Element? {
sorted().minConsecutiveDiff()
}
}
Here is one way using forEach
var min: Double = array.max()!
var previous: Double?
array.forEach {
if let prev = previous, min > abs($0 - prev) {
min = abs($0 - prev)
}
previous = $0
}
another option is to use reduce(into:) with a tuple
let min = array.reduce(into: (Double, Double)(array.first!, 0)) {
if abs($1 - $0.1) < $0.0 {
$0.0 = abs($1 - $0.1)
}
$0.1 = $1
}.0
which both gives 10.18 as the smallest difference.

A is an arrays: determine if there are two integers that are present in A the same number of times

For example: A=[1,2,2,3,4,4,5]->true; A=[1,2,2,3,3,3,4,4,4,4]->false.
proc(A){
list = newList()
for (i=1 to length[A]) {
occ = 0
n = a[i]
for (j = 1 to length[A]) {
if(a[j] == n)
occ++
}
list.append(occ)
}
but dosen't work because in the list will be repeated elements.I thought about using an algorithm similar to countingSort but I don't know the length of the support vector.
Any help? In pseudocode will be fine.
Thank you.
With the use of data structures like map and set, this task could be accomplished very easily.
Algorithm:-
-> Loop through the array and store it in hashmap with key as the value of the array element and value as the count of it's occurrence.
-> Create an empty set
-> Loop through the map and keep storing the value of every key in the set and if somewhere in between looping u come across any value that's already there in the set, then return true else if u reach the end of map, then return false.
Let's look as Pseudocode now.
Pseudocode:-
-> we have input array as arr and length n
-> we create an empty map - m[int, int]
-> for (i -> 0 to n-1)
{
m[arr[i]]++;
}
-> This in the end will give us our map which we want with key as the array element and value as it's count
-> create a set - s
-> iterate over map m as key -> value
{
if (value present in s) {
return true
}
s.insert(value)
}
-> If we reach here then it means we never came across any pair of elements whose occurrence is same, so return false.
Hope this helps!

Type Int does not conform to protocol sequence

I have the following code in Swift 3:
var numbers = [1,2,1]
for number in numbers.count - 1 { // error
if numbers[number] < numbers[number + 1] {
print(number)
}
}
I am checking if the value on the index [number] is always higher than the value on the index [number + 1]. I am getting an error:
Type Int does not conform to protocol sequence
Any idea?
It may be swift.
You can use this iteration.
for number in 0..<(numbers.count-1)
The error is because Int is not a Sequence. You can create a range as already suggested, which does conform to a sequence and will allow iteration using for in.
One way to make Int conform to a sequence is:
extension Int: Sequence {
public func makeIterator() -> CountableRange<Int>.Iterator {
return (0..<self).makeIterator()
}
}
Which would then allow using it as a sequence with for in.
for i in 5 {
print(i)
}
but I wouldn't recommend doing this. It's only to demonstrate the power of protocols but would probably be confusing in an actual codebase.
From you example, it looks like you are trying to compare consecutive elements of the collection. A custom iterator can do just that while keeping the code fairly readable:
public struct ConsecutiveSequence<T: IteratorProtocol>: IteratorProtocol, Sequence {
private var base: T
private var index: Int
private var previous: T.Element?
init(_ base: T) {
self.base = base
self.index = 0
}
public typealias Element = (T.Element, T.Element)
public mutating func next() -> Element? {
guard let first = previous ?? base.next(), let second = base.next() else {
return nil
}
previous = second
return (first, second)
}
}
extension Sequence {
public func makeConsecutiveIterator() -> ConsecutiveSequence<Self.Iterator> {
return ConsecutiveSequence(self.makeIterator())
}
}
which can be used as:
for (x, y) in [1,2,3,4].makeConsecutiveIterator() {
if (x < y) {
print(x)
}
}
In the above example, the iterator will go over the following pairs:
(1, 2)
(2, 3)
(3, 4)
This maybe a little late but you could have done:
for number in numbers { }
instead of:
for number in numbers.count - 1 { }
For a for loop to work a sequence (range) is needed. A sequence consists of a stating a value, an ending value and everything in between. This means that a for loop can be told to loop through a range with ether
for number in 0...numbers.count-1 { } `or` for number in numbers { }
Both example give the nesasery sequences. Where as:
for number in numbers.count - 1 { }
Only gives one value that could either be the starting or the ending value, making it impossible to work out how many time the for loop will have to run.
For more information see Apple's swift control flow documnetation
This error can also come about if you try to enumerate an array instead of the enumerated array. For example:
for (index, element) in [0, 3, 4] {
}
Should be:
for (index, element) in [0, 3, 4].enumerated() {
}
So first you need to understand what is sequence..
A type that provides sequential, iterated access to its elements.
A sequence is a list of values that you can step through one at a time. The most common way to iterate over the elements of a sequence is to use a for-in loop:
let oneTwoThree = 1...3. // Sequence
for loop actually means
For number in Sequences {}
So you need to use
for number in 0..<(numbers.count-1) {}
The error is because number is not an index, but the element of the array on each iteration. You can modify your code like this:
var numbers = [1,2,1,0,3]
for number in 0..<numbers.count - 1 {
if numbers[number] < numbers[number + 1] {
print(numbers[number])
}
}
Or there is a trick using the sort method, but that's kind of a hack (and yes, the subindexes are right, but look like inverted; you can try this directly on a Playground):
var numbers = [1,2,1,0,3]
numbers.sort {
if $0.1 < $0.0 {
print ($0.1)
}
return false
}
For me, this error occurred when I tried writing a for loop, not for an array but a single element of the array.
For example:
let array = [1,2,3,4]
let item = array[0]
for its in item
{
print(its)
}
This gives an error like: Type Int does not conform to protocol 'sequence'
So, if you get this error in for loop, please check whether you are looping an array or not.

Swift Dictionary of Arrays

I am making an app that has different game modes, and each game mode has a few scores. I am trying to store all the scores in a dictionary of arrays, where the dictionary's key is a game's id (a String), and the associated array has the list of scores for that game mode. But when I try to initialize the arrays' values to random values, Swift breaks, giving me the error below. This chunk of code will break in a playground. What am I doing wrong?
let modes = ["mode1", "mode2", "mode3"]
var dict = Dictionary<String, [Int]>()
for mode in modes
{
dict[mode] = Array<Int>()
for j in 1...5
{
dict[mode]?.append(j)
let array:[Int] = dict[mode]!
let value:Int = array[j] //breaks here
}
}
ERROR:
Execution was interrupted, reason: EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP, subcode=0x0).
Your problem is array subscripts are zero-based. So when you write:
var a: [Int] = []
for i in 1...5 {
a.append(42)
println(a[i])
}
you will get a runtime error, because first time around the loop you are subscripting a[1] when there is only an a[0]. In your code, you either need to do for j in 0..<5 or let value = array[j-1].
By the way, even though it’s perfectly safe to do dict[mode]! (since you just added it), it’s a habit best avoided as one of these days your code won’t be as correct as you think, and that ! will explode in your face. There’s almost always a better way to write what you want without needing !.
Also, generally speaking, whenever you use array subscripts you are risking an accidental screw-up by accidentally addressing an out-of-bounds index like here. There are lots of alternatives that mean actually using a[i] is easy to avoid:
If you want the indices for a collection (like an array), instead of:
for i in 0..<a.count { }
you can write
for i in indices(a) { }
If you want to number the elements in an array, instead of
for i in indices(a) { println("item \(i) is \(a[i])" }
you can write
for (i, elem) in enumerate(a) { println("item \(i) is \(elem)") }
If the collection happens to have an Int for an index (such as Array), you can use i as an index, but if it doesn’t (such as String) an alternative to get the index and element is:
let s = "hello"
for (idx, char) in Zip2(indices(s),s) { }
If you want the first or last element of an array, instead of:
if a.count > 0 { let x = a[0] }
if a.count > 0 { let x = a[a.count - 1] }
you can write
if let first = a.first { let x = first }
if let last = a.last { let x = first }
Prefer map, filter and reduce to for loops in general (but don’t obsess over it, sometimes a for loop is better)

Resources