Is there any way to have an n dimensional array in swift? I would like to be able to make a function that creates an array with n dimensions but I cannot figure out how.
Basically something like this:
func ndarray <T> (dimensions: Int...) -> [[T]] { // What do I tell it I return?
var out
for d in dimensions {
out = Array<T>(repeating: out, count: d)
}
return out
}
The above code does not work for obvios reasons but, I think it points out the main problems I am having:
How do I define a return type
How do I actually create the array
Once created how do I traverse and populate the array
Here is the implementation of an N-Dimensional Array. It uses a normal array internally for storage and converts the multi-dimensional indices into a single index for the internal array.
struct NDimArray<T> {
let dimensions: [Int]
var data: [T]
init(dimensions: Int..., initialValue: T) {
self.dimensions = dimensions
data = Array(repeating: initialValue, count: dimensions.reduce(1, *))
}
init(dimensions: Int..., initUsing initializer: () -> T) {
self.dimensions = dimensions
data = (0 ..< dimensions.reduce(1, *)).map { _ in initializer() }
}
// Compute index into data from indices
private func computeIndex(_ indices: [Int]) -> Int {
guard indices.count == dimensions.count else { fatalError("Wrong number of indices: got \(indices.count), expected \(dimensions.count)") }
zip(dimensions, indices).forEach { dim, idx in
guard (0 ..< dim) ~= idx else { fatalError("Index out of range") }
}
var idx = indices
var dims = dimensions
var product = 1
var total = idx.removeLast()
while !idx.isEmpty {
product *= dims.removeLast()
total += (idx.removeLast() * product)
}
return total
}
subscript(_ indices: Int...) -> T {
get {
return data[computeIndex(indices)]
}
set {
data[computeIndex(indices)] = newValue
}
}
}
Example:
// Create a 3 x 4 x 5 array of String with initial value ""
var arr = NDimArray<String>(dimensions: 3, 4, 5, initialValue: "")
for x in 0 ..< 3 {
for y in 0 ..< 4 {
for z in 0 ..< 5 {
// Encode indices in the string
arr[x, y, z] = "(\(x),\(y),\(z))"
}
}
}
// Show internal storage of data
print(arr.data)
["(0,0,0)", "(0,0,1)", "(0,0,2)", "(0,0,3)", "(0,0,4)", "(0,1,0)", "(0,1,1)", "(0,1,2)", "(0,1,3)", "(0,1,4)", "(0,2,0)", "(0,2,1)", "(0,2,2)", "(0,2,3)", "(0,2,4)", "(0,3,0)", "(0,3,1)", "(0,3,2)", "(0,3,3)", "(0,3,4)", "(1,0,0)", "(1,0,1)", "(1,0,2)", "(1,0,3)", "(1,0,4)", "(1,1,0)", "(1,1,1)", "(1,1,2)", "(1,1,3)", "(1,1,4)", "(1,2,0)", "(1,2,1)", "(1,2,2)", "(1,2,3)", "(1,2,4)", "(1,3,0)", "(1,3,1)", "(1,3,2)", "(1,3,3)", "(1,3,4)", "(2,0,0)", "(2,0,1)", "(2,0,2)", "(2,0,3)", "(2,0,4)", "(2,1,0)", "(2,1,1)", "(2,1,2)", "(2,1,3)", "(2,1,4)", "(2,2,0)", "(2,2,1)", "(2,2,2)", "(2,2,3)", "(2,2,4)", "(2,3,0)", "(2,3,1)", "(2,3,2)", "(2,3,3)", "(2,3,4)"]
print(arr[2, 2, 2]) // "(2,2,2)"
print(arr[3, 0, 0]) // Fatal error: Index out of range
print(arr[0, 4, 0]) // Fatal error: Index out of range
print(arr[2]) // Fatal error: Wrong number of indices: got 1, expected 3
Initializing an Array with a Reference Type
As #DuncanC noted in the comments, you have to be careful when initializing an array with a value which is a reference type, because the array will be filled with references to the object and modifying the object at any index will modify all of them.
To solve this, I added a second initializer:
init(dimensions: Int..., initUsing initializer: () -> T)
which takes a closure () -> T which can be used to create a new object for each element of the array.
For example:
class Person {
var name = ""
}
// Pass a closure which creates a `Person` instance to fill the array
// with 25 person objects
let arr = NDimArray(dimensions: 5, 5, initUsing: { Person() })
arr[3, 3].name = "Fred"
arr[2, 2].name = "Wilma"
print(arr[3, 3].name, arr[2, 2].name)
Fred Wilma
Nope, it's not possible. Array dimensions is something that needs to be determined at compile time, while the argument you want to pass to the initializer will not be known until runtime. If you really want to achieve something like this, then you'll need to move the array indexing from compile time to runtime, e.g. by accessing the array via an array of indexes. Still you don't have compile validation, since the array length can at runtime to not match the dimensions of the array.
This problem is similar to the one that attempts to convert a tuple to an array.
Supposre I have an input array of integers. I want to split this array in multiple array based on the missing integer and append it in a new Array. I think split can be used here but not sure how to do it. I want arrayFinal only.
myArray = [0,1,2,4,7,8]
Desired Output
arrayOne = [0,1,2]
arrayTwo = [4]
arrayThree = [7,8]
arrayFinal = [[0,1,2], [4], [7,8]]
That's an algorithm you're asking for so there are a dozen different ways to do it. Since you are going to have to walk through the array's contents to find the missing integers, I would just create an array and append the numbers to it as you go, then create a new array whenever you hit a gap.
You'll probably have to adjust this for any special cases you might have. "Will this always start at 0 and move in a positive direction?" etc.
Try this out:
func splitByMissingInteger(array: [Int]) -> [[Int]]? {
var arrayFinal :[[Int]] = [ [Int]() ]
var i = 0
for num in array{
if arrayFinal[i].isEmpty || (arrayFinal[i].last == nil){
arrayFinal[i].append(num)
} else if num == (arrayFinal[i].last! + 1){
arrayFinal[i].append(num)
} else {
i += 1
arrayFinal.append([Int]())
arrayFinal[i].append(num)
}
}
return arrayFinal
}
You can just sort your array and iterate them in order. Check if the element minus one is equal to the last element of your 2D array, if true append otherwise append a new array with the element and increase the index of the subarrays:
extension Collection where Element == Int {
func grouped() -> [[Element]] {
let elements = Set(self).sorted()
guard let first = elements.first else { return [] }
var result = [[first]]
var i = 0
for element in elements.dropFirst() {
if element-1 == result[i].last! {
result[i].append(element)
} else {
result.append([element])
i += 1
}
}
return result
}
}
let myArray = [0,1,2,4,7,8]
let grouped = myArray.grouped() // [[0, 1, 2], [4], [7, 8]]
Is there any best method to check if elements in array are in consecutive order?
Eg:
[1,2,3,4,5] // returns true
[1,2,4,3,5] // returns false
Currently what I implement is to take difference of elements and if the diff is 1 then I say it is in consecutive order.
I'm looking for any improved approach. I think of adding extension to Array but not sure how to implement this.
Given your array
let list = [1,2,3,4,5]
you can use some Functional Programming magic
let consecutives = list.map { $0 - 1 }.dropFirst() == list.dropLast()
If this is a one-off question, then any little for-loop is fine, but it's an interesting problem to explore generic solutions. First, I'm assuming you mean that each element must be one greater than the one before, not just in order.
Let's build a generic way to answer "do all pairs of elements in this collection obey some rule." First, it'd be really nice to have a generic way to say "do all?"
extension Sequence {
func all(pass predicate: (Element) -> Bool) -> Bool {
// If nothing is false, everything is true
return !self.contains(where: { !predicate($0) })
}
}
This returns whether all elements of a sequence obey some rule.
Now we can ask the question: do all pair-wise elements of a collection obey some rule:
extension Collection {
func passesForConsecutiveValues(_ predicate:(Element, Element) -> Bool) -> Bool {
return zip(self, dropFirst()).all(pass: predicate)
}
}
zip(x, x.dropFirst() just creates "pair-wise elements", and then we ask "do they all satisfy our rule?" For example:
// Are all elements one more than their predecessor?
[1,2,4,5].passesForConsecutiveValues { $1 == $0 + 1 } // true
Now you may have noticed that I switched from Sequence to Collection in the middle there. Why? Because zip(x, x.dropFirst()) isn't defined on arbitrary sequences. You may only be allowed to iterate over a sequence once. Unfortunately there's no way to know; it's considered "special knowledge about the sequence" in the docs. Bleh. I miss Scala's TraversableOnce vs. Sequence that moves the requirement into the type.
That said, we absolutely can build this for Sequence. We just have to build a replacement for zip(x, x.dropFirst()). We'll call it pairwise and it'll return an iterator:
extension Sequence {
func pairwise() -> AnyIterator<(Element, Element)> {
var it = makeIterator()
guard var last_value = it.next() else { return AnyIterator{ return nil } }
return AnyIterator {
guard let value = it.next() else { return nil }
defer { last_value = value }
return (last_value, value)
}
}
}
And with that, we can build this on Sequence:
extension Sequence {
func passesForConsecutiveValues(_ predicate:(Element, Element) -> Bool) -> Bool {
return pairwise().all(pass: predicate)
}
}
"Currently what I implement is to take difference of elements and if
the diff is 1 then I say it is in sequence."
Based on your statement above, it seems your want to, for an array of integers, see if all members are consecutive.
You've already described the logic for this algorithm: you could implement it e.g. using a for ... in ... where loop, with a body which is only ever entered when the where clause identifies two subsequent elements which are not in consecutive order. E.g.:
extension Array where Element == Int {
func numbersAreConsecutive() -> Bool {
for (num, nextNum) in zip(self, dropFirst())
where (nextNum - num) != 1 { return false }
return true
}
}
var arr = [1, 2, 3, 4, 5]
print(arr.numbersAreConsecutive()) // true
arr = [1, 2, 4, 5]
print(arr.numbersAreConsecutive()) // false
arr = [1]
print(arr.numbersAreConsecutive()) // true
arr = []
print(arr.numbersAreConsecutive()) // true
arr = [2, 1]
print(arr.numbersAreConsecutive()) // false
Extending the extension to all types conforming to Integer:
extension Array where Element: Integer {
func numbersAreConsecutive() -> Bool {
for (num, nextNum) in zip(self, dropFirst())
where (nextNum - num) != 1 { return false }
return true
}
}
It will return the true if the sequence is expected otherwise it will return the false
It has two check
1.Checking whether the array is sequence(Find the array is sequence)
1.1 Sortedarray[0] + arraycount multiple with sequence (1,2,3, etc) and minus the sequence.
1.2 compare the above calculated value with last value of sorted array. if it matche we could consider The array is sequence.
2. Compare the source array and sorted array to confirm it is in order
isSeq([4,5,6,7],sequence:1) **return True**
isSeq([100,102,104,106,108],sequence:2) **return True**
isSeq([100,103,106,109,110],sequence:3) **return false**
func isSeq(_ arrayValue:[Int],sequence:Int) ->Bool{
let sortedValue = arrayValue.sorted()
if(sortedValue[0] + (sortedValue.count * sequence) - sequence == sortedValue[sortedValue.count - 1]){
if(arrayValue == sortedValue){
return true
}
}
return false;
}
Quick question please about the efficiency of higher order swift functions with large input data. During a recent test I had a question about finding 'equlibirum indexes' in arrays- i.e. the index of an array where the sum of all elements below the index equals the sum of all elements above the index
An equilibrium index of this array is any integer P such that 0 ≤ P <
N and the sum of elements of lower indices is equal to the sum of
elements of higher indices, i.e.
A[0] + A[1] + ... + A[P−1] = A[P+1] + ... + A[N−2] + A[N−1].
The challenge was to write a short function which computed the first (or any) index which was considered 'equilibirum'.
I put together a simple snippet which scored highly but failed some of the 'performance' tests which used large input data (array sizes around 100,000).
Here's the code
public func solution(inout A : [Int]) -> Int {
var index = 0;
for _ in A {
let sumBefore = A[0...index].reduce(0) { $0 + $1 }
let sumAfter = A[index...A.count-1].reduce(0) { $0 + $1 }
if (sumBefore == sumAfter) { return index; }
index += 1;
}
return -1;
}
Would anyone please be able to explain why the code performs so poorly with large sets of data, or any recommended alternatives?
Here, for example is a description of a failing perfomance test:
Large performance test, O(n^2) solutions should fail.
✘ TIMEOUT ERROR
running time: >6.00 sec., time limit: 0.22 sec.
It looks like the challenge is failing because your solution is O(n^2).
Your for loop, along with 2 sequential reduces inside, make your solution ~ O(2*n^2) since reduce goes through all the elements again.
A simpler solution is to first compute the whole sum, and then iterate through the elements once, subtracting each value from the whole sum, one by one, thus having access to the left and right sums, for comparison.
Using Swift 3.0, Xcode 8:
func findEquilibriumIndex(in array: [Int]) -> Int? {
var leftSum = 0
var rightSum = array.reduce(0, combine: +)
for (index, value) in array.enumerated() {
rightSum -= value
if leftSum == rightSum {
return index
}
leftSum += value
}
return nil
}
let sampleArray = [-7, 1, 5, 2, -4, 3, 0]
findEquilibriumIndex(in: sampleArray)
The problem is not that "the built-in functions perform so poorly."
Your solution is slow because in each iteration, N elements are
added (N being the length of the array). It would be more efficient
to compute the total sum once and update the "before sum"
and "after sum" while traversing through the array. This reduces
the complexity from O(N^2) to O(N):
public func solution(A : [Int]) -> Int {
var sumBefore = 0
var sumAfter = A.reduce(0, combine: +)
for (idx, elem) in A.enumerate() {
sumAfter -= elem
if sumBefore == sumAfter {
return idx
}
sumBefore += elem
}
return -1
}
(Swift 2.2, Xcode 7.3.1)
Remarks:
There is no reason to pass the array as inout parameter.
An operator (in this case +) can be passed as a argument to the reduce() function.
enumerate() returns a sequence of array indices together with
the corresponding element, this saves another array access.
Note also that a more "Swifty" design would be to make the return type
an optional Int? which is nil if no solution was found.
The incrementalSums extension
If you define this extension
extension Array where Element : SignedInteger {
var incrementalSums: [Element] {
return Array(reduce([0]) { $0.0 + [$0.0.last! + $0.1] }.dropLast())
}
}
given an array of Int(s) you can build an array where the Int at the n-th position represents the sum of the values from 0 to (n-1) in the original array.
Example
[1, 2, 3, 10, 2].incrementalSums // [0, 1, 3, 6, 16]
The equilibriumIndex function
Now you can build a function like this
func equilibriumIndex(nums: [Int]) -> Int? {
let leftSums = nums.incrementalSums
let rightSums = nums.reversed().incrementalSums.reversed()
return Array(zip(leftSums, rightSums)).index { $0 == $1 }
}
Here is a functional version of the solution in Swift 3
let total = sampleArray.reduce(0,+)
var sum = 0
let index = sampleArray.index{ v in defer {sum += v}; return sum * 2 == total - v }
If I understand correctly the element at the resulting index is excluded from the sum on each side (which I'm not certain the other solutions achieve)