I want to add one to the array values that are next to the current iteration.
Although at the end result is right, if we see the print(item) result, it still prints the old values.
var arr3 = [1,2,3]
for (index,item) in arr3.enumerated() {
if index+1 == arr3.count {
// Do nothing
} else {
arr3[index + 1] = arr3[index+1] + 1
}
print(item)
}
print(arr3)
Result :
1
2
3
[1,3,4]
Expected :
1
3
4
[1,3,4]
How is this possible?
You might expect the loop using enumerated() to behave the same as looping over the indices and having let item = arr3[index]:
for index in arr3.indices {
let item = arr3[index]
print(item)
if index+1 != arr3.count {
arr3[index + 1] += 1
}
}
However, this is not true. enumerated() produces an EnumeratedSequence<[Int]>. (See the source code for EnumeratedSequence and enumerated()). To create an EnumeratedSequence, the original array arr3 is passed to its initialiser:
public func enumerated() -> EnumeratedSequence<Self> {
return EnumeratedSequence(_base: self)
}
As you may know, Array is a (copy-on-write) value type. When you modify arr3 in the loop, a modified copy is created and assigned to arr3, and the array that the EnumeratedSequence has (i.e. the array over which the loop is iterating), is unaffected. enumerated() is sort of creating a "snapshot" of the array at the time when you called it, so all the print(item) will only print the old items.
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]]
So say I have an array:
var stringArray = ["a","b","c","d","e","f","g","h","i","j"]
Now, how do I delete "a", "c", "e", "g", and "i" (all the even number indexes from the array)?
Thanks!
Instead of using C-style for-loops (which are set to be deprecated in an upcoming version of Swift), you could accomplish this using strides:
var result = [String]()
for i in stride(from: 1, through: stringArray.count - 1, by: 2) {
result.append(stringArray[i])
}
Or for an even more functional solution,
let result = stride(from: 1, to: stringArray.count - 1, by: 2).map { stringArray[$0] }
Traditional
var filteredArray = []
for var i = 1; i < stringArray.count; i = i + 2 {
filteredArray.append(stringArray[i])
}
Functional alternative
var result = stringArray.enumerate().filter({ index, _ in
index % 2 != 0
}).map { $0.1 }
enumerate takes a array of elements and returns an array of tuples where each tuple is an index-array pair (e.g. (.0 3, .1 "d")). We then remove the elements that are odd using the modulus operator. Finally, we convert the tuple array back to a normal array using map. HTH
There are a bunch of different ways to accomplish this, but here are a couple that I found interesting:
Using flatMap() on indices:
let result: [String] = stringArray.indices.flatMap {
if $0 % 2 != 0 { return stringArray[$0] }
else { return nil }
}
Note: result needs to be defined as a [String] otherwise the compiler doesn't know which version of flatMap() to use.
Or, if you want to modify the original array in place:
stringArray.indices.reverse().forEach {
if $0 % 2 == 0 { stringArray.removeAtIndex($0) }
}
In this case you have to call reverse() on indices first so that they're enumerated in reverse order. Otherwise by the time you get to the end of the array you'll be attempting to remove an index that doesn't exist anymore.
Swift 4.2
A function accepting generics and producing reduced result
func stripElements<T>(in array:[T]) -> [T] {
return array.enumerated().filter { (arg0) -> Bool in
let (offset, _) = arg0
return offset % 2 != 0
}.map { $0.element }
}
I am trying to compare two arrays (array1, array2) and if a specific key value is contained in array2, the key value in array1 that contains the array2 value needs to be printed out with its 'indexPath'.
The code I have almost works however, the app crashes because while going trough the keys, array2 goes out of range because it contains less indexes that the array1
How can I make the code look for matches if other array is smaller?
let array1 = [["aaa","bbb","ccc","ddd","eee"], ["fff","ggg","hhh","matched","iii"], ["lll","mmm","nnn","ooo","ppp"], ["666","777","888","999","000"] ] //4 elements
let countArray1 = array1.enumerate()
let array2 = [["111","222"], ["333","444"], ["matched","555"]] // 3 elements
for (index, element) in countArray1{
let containedValue = array1[index].contains(array2[index][0])
if (containedValue) == true{
print("The index of the contained value is: ????") //error
}
}
I would turn the smaller 2D array into a 1D array and then loop through the both dimensions of the bigger array and use NSArray.contains:
DISCLAIMER: this code is untested. #Community: if you stumble upon this and notice a mistake or something that can be better written, comment or edit. I use Obj-C more than Swift.
//convert 2D array to 1D
func from2Dto1D(array: NSArray) -> NSArray {
var newArr = NSMutableArray()
for (d1) in array {
for (d2) in d1 {
newArr.append(d2)
}
}
return newArr as NSArray
}
func hasMatch(array1: NSArray, array2: NSArray) -> boolean {
var bigger: NSArray
var smaller: NSArray
if (array1.count > array2.count){
bigger = array1
smaller = from2Dto1D(array2)
}else{
bigger = array2
smaller = from2Dto1D(array1)
}
for (d1) in bigger{
for (item) in d1 {
if (smaller.contains(item)){
print("Match found");
return true
}
}
}
return false
}
You could flatten out both the arrays and then enumerate them to check which index the objects match at.
let array1 = [["aaa","bbb","ccc","ddd","eee"], ["fff","ggg","hhh","matched","iii"], ["lll","mmm","nnn","ooo","ppp"], ["666","777","888","999","000"] ] //4 elements
let array2 = [["111","222"], ["333","444"], ["matched","555"]] // 3 elements
let flat1 = Array(array1.flatten())
let flat2 = Array(array2.flatten())
for (index1,object1) in flat1.enumerate() {
for (index2,object2) in flat2.enumerate() {
if object2 == object1 {
print("index1 is: \(index1). Index 2 is \(index2)")
}
}
}