I have some arrays:
var arrayOne = [String]()
var arrayTwo = [String]()
var arrayThree = [String]()
Then I write a function. I give a number, it returns my one of these arrays:
func get_array(aNumber:Int) -> NSArray {
var arr = self.arrayOne //default
if aNumber == 1 {
arr = self.arrayOne
} else if aNumber == 2 {
arr = self.arrayTwo
} else if aNumber == 3 {
arr = self.arrayThree
}
return arr!
}
Then for instance I do:
var myArray = get_array(2)
myArray.append("hello")
NSLog("myArray: %#", myArray) // Ok, myArray was modified!!
NSLog("arrayTwo: %#", arrayTwo) // **Shit, arrayTwo was not modified!!** I was expecting myArray to be pointing to arrayTwo, so they are the same object
How can do this???
Swift arrays are value types. It means that
let array2 = array1
makes a copy of array1. So when you access array2 it is not the same array anymore as array1, it is another object with the same content.
This is different from NSArray and NSMutableArray which are a reference type: when you do
let nsarray2 = nsarray1
this time nsarray2 is a reference to nsarray1 and they are actually the same object.
In Swift Arrays are value types so they get copied if you assign, return or pass as parameter.
To make this work as expected you have to make a wrapper (class):
class ArrayWrapper<T> {
var array: [T]
init(_ array: [T] = []) {
self.array = array
}
}
var arrayOne = ArrayWrapper<String>()
var arrayTwo = ArrayWrapper<String>()
var arrayThree = ArrayWrapper<String>()
func get_array(aNumber:Int) -> ArrayWrapper<String> {
var arr = self.arrayOne //default
if aNumber == 1 {
arr = self.arrayOne
} else if aNumber == 2 {
arr = self.arrayTwo
} else if aNumber == 3 {
arr = self.arrayThree
}
return arr
}
// in case of your function I would suggest to use switch instead:
func getArray(aNumber:Int) -> ArrayWrapper<String> {
switch aNumber {
case 1: return self.arrayOne
case 2: return self.arrayTwo
case 3: return self.arrayThree
default: return self.arrayOne
}
}
// so you modify the Array as following:
var myArray = get_array(2)
myArray.array.append("hello")
Related
I am having problems creating a function that accepts an array and returns a two-dimensional array. An an example like [1,2,3,4,5,6] = [[1,2],[3,4],[5,6]].
So far I only have :
func spiltArray(numbers:[Int])->[[Int]]{
}
func spiltArray(numbers:[Int])->[[Int]]{
var result:[[Int]] = []
if numbers.count == 0{
return result
}
let split = 2
var arr:[Int] = []
for item in numbers{
if(arr.count>=split){
result.append(arr)
arr = []
}
arr.append(item)
}
result.append(arr)
return result
}
So I have this method to get an array of random ints between 1-9, a random number of times between 1 and 7.
let n = arc4random_uniform(7) + 1
var arr: [UInt32] = []
for _ in 0 ... n {
var temp = arc4random_uniform(9) + 1
while arr.contains(temp) {
temp = arc4random_uniform(9) + 1
}
print(temp)
arr.append(temp)
}
print(arr)
So that gets me an array like [1,4,2] or [5,7,3,4,6]. And I have a method to turn another array of strings into a enumerated dictionary.
var someArray: [String] = ["War", "Peanuts", "Cats", "Dogs", "Nova", "Bears", "Pigs", "Packers", "Mango", "Turkey"]
extension Collection {
var indexedDictionary: [Int: Element] {
return enumerated().reduce(into: [:]) { $0[$1.offset] = $1.element }
}
}
let dict1 = someArray.indexedDictionary
print(dict1)
giving me the indexed dictionary
[1:"War", 2:"Peanuts",..etc]
MY question is using the Ints of the random array how do I create a new dictionary that only includes those keys and their values?
So for example if arr = [3,1,5]
how do I get a new dictionary of
[3:"dogs", 1:"Peanuts",5:"Bears"].
This should do it:
let finalDict = dict1.filter { arr.contains($0.key) }
Update:
You can even go a step further and skip the whole strings to array mapping. So remove
extension Collection {
var indexedDictionary: [Int: Element] {
return enumerated().reduce(into: [:]) { $0[$1.offset] = $1.element }
}
}
let dict1 = someArray.indexedDictionary
print(dict1)
and just use this:
Swift 4:
let finalArray = someArray.enumerated().flatMap { arr.contains($0.offset) ? $0.element : nil }
Swift 4.1:
let finalArray = someArray.enumerated().compactMap { arr.contains($0.offset) ? $0.element : nil }
Update 2:
If you need a dictionary and not an array in the end use this:
Swift 4:
let finalDict = someArray.enumerated().flatMap { randomInts.contains($0.offset) ? ($0.offset, $0.element) : nil }.reduce(into: [:]) { $0[$1.0] = $1.1 }
Swift 4.1:
let finalDict = someArray.enumerated().compactMap { randomInts.contains($0.offset) ? ($0.offset, $0.element) : nil }.reduce(into: [:]) { $0[$1.0] = $1.1 }
In swift, I want to categorize items in an existing array and place them accordingly in one new string.
Here is an example of what I want to do:
originalArray = ["hotdog","fries","hotdog","coke","coke","fries","hotdog"]
resultingString = "hotdog x 3, fries x 2, coke x 2"
How would I go about doing this?
Try this:
let originalArray = ["hotdog","fries","hotdog","coke","coke","fries","hotdog"]
var dict = [String: Int]()
let resultString = originalArray.reduce(dict) { _, element in
if dict[element] == nil {
dict[element] = 1
} else {
dict[element]! += 1
}
return dict
}
.map { "\($0) x \($1)" }
.joinWithSeparator(", ")
If you want to keep the original order of the array (ie: hotdog, fries, coke), the code is slightly more complicated:
let originalArray = ["hotdog","fries","hotdog","coke","coke","fries","hotdog"]
var dict = [String: (index: Int, count: Int)]()
let resultString = originalArray.enumerate()
.reduce(dict) { _ , e in
if let value = dict[e.element] {
dict[e.element] = (index: value.index, count: value.count + 1)
} else {
dict[e.element] = (index: e.index, count: 1)
}
return dict
}
.sort { return $0.1.index < $1.1.index }
.map { "\($0) x \($1.count)" }
.joinWithSeparator(", ")
print(resultString)
I think this will help you:
let originalArray = ["hotdog","fries","hotdog","coke","coke","fries","hotdog"]
var resultingString = ""
var counts:[String:Int] = [:]
for item in originalArray {
counts[item] = (counts[item] ?? 0) + 1
}
resultingString = counts.map { (key, value) -> String in
return "\(key) x \(value)"
}.joinWithSeparator(",")
print(resultingString)
Here is the output: coke x 2, hotdog x 3, fries x 2
I'm trying to extend Array to return a sub array.
the line let b = arr.objectsAtIndexes([1,3,5]) produces the error "Value of type '[Int]' has no member 'objectsAtIndexes'
import Foundation
var arr = [Int](6..<19)
let b = arr.objectsAtIndexes([1,3,5])
b = b.append(1)
extension Array {
func objectsAtIndexes(indexes: [Int]) -> [Element] {
var returnArray = [Element]()
for i in indexes {
returnArray.append(self[i])
}
return returnArray
}
}
Just use that extension below the extension declaration this way:
import Foundation
extension Array {
func objectsAtIndexes(indexes: [Int]) -> [Element] {
var returnArray = [Element]()
for i in indexes {
returnArray.append(self[i])
}
return returnArray
}
}
var arr = [Int](6..<19)
var b = arr.objectsAtIndexes([1,3,5])
b = b.append(1)
And replace this line:
b = b.append(1)
With this line:
b.append(1)
And your result will be:
After defining the extension, you should call your method. Check this Extension reference
also .append don't return any value, so don't assign it
extension Array {
func objectsAtIndexes(indexes: [Int]) -> [Element] {
var returnArray = [Element]()
for i in indexes {
returnArray.append(self[i])
}
return returnArray
}
}
var arr = [Int](6..<19)
var b = arr.objectsAtIndexes([1,3,5])
// Do not assign to b
b.append(1)
As I try to learn Swift 3, I am attempting to "Wrap an Array of Elements". In Swift 3 Playgrounds, I was able to implement code that wraps an array. My problem occurs when I try to create a function that implements my code.
If you take the following code and copy-paste it to a Swift 3 Playground then you will likely see what I am trying to do. Change the selectedElement and on the right you will see the correct newArray. You can interchange the different elements for the selectedElement and the newArray will change accordingly.
I noted one of my failed attempts at turning this into a function.
import UIKit
let myArray = ["a", "b", "c", "d", "e"]
let selectedElement = "a"
//func arrayWrapper(inputArray: Array<String>) -> Array<String> {
var oldArray = [String]()
var priorElements = [String]()
var newArray = [String]()
for element in myArray {
if element == selectedElement || oldArray.count > 0 {
oldArray.append(element)
} else {
priorElements.append(element)
}
newArray = oldArray + priorElements
}
//return newArray
//}
priorElements
oldArray
oldArray + priorElements
newArray
Your method works fine.
The only problem I see is that you are trying to access the variables created inside the function outside of the function scope.
//priorElements
//oldArray
//
//oldArray + priorElements
arrayWrapper(inputArray: myArray)
Well, your non-function solution to this problem takes two inputs - the array you want to wrap, and the element you want it to wrap at. Therefore, your function should have two parameters as well:
// note the second parameter
func arrayWrapper(inputArray: Array<String>, selectedElemented: String) -> Array<String> {
var oldArray = [String]()
var priorElements = [String]()
var newArray = [String]()
for element in myArray {
if element == selectedElement || oldArray.count > 0 {
oldArray.append(element)
} else {
priorElements.append(element)
}
newArray = oldArray + priorElements
}
return newArray
}
Here is a more general version of this function, as an extension of Array:
extension Array where Element : Equatable {
func wrap(around selectedElement: Element) -> Array<Element> {
var oldArray = [Element]()
var priorElements = [Element]()
var newArray = [Element]()
for element in self {
if element == selectedElement || oldArray.count > 0 {
oldArray.append(element)
} else {
priorElements.append(element)
}
newArray = oldArray + priorElements
}
return newArray
}
}
// usage
myArray.wrap(around: selectedElement)