var a=[0,0,0,0]
var b=[0,0,0,0]
for i in 0..<4{
var g=i%2==0 ? a:b
g[i]+=1
//10 more lines of code about array g
}
I want to implement something like whenever i is an even number increment the i position of A by 1, and if i is odd increment the i position of B by 1.
The expecting result is A=[1,0,1,0] and B is [0,1,0,1]
Here modifying the array g will not affect the original array because of deep copy. Are there any ways to modify array a and b without using if...else statement?
You have to modify a value type directly, a possible solution is
var a = [0,0,0,0]
var b = [0,0,0,0]
for i in 0..<4 {
i.isMultiple(of: 2) ? (a[i] += 1) : (b[i] += 1)
}
Another solution is to use a class (reference type) wrapper
class Wrapper {
var array = [0,0,0,0]
}
let a = Wrapper()
let b = Wrapper()
for i in 0..<4 {
let g = i.isMultiple(of: 2) ? a : b
g.array[i] += 1
}
print(a.array)
print(b.array)
var a=[0,0,0,0]
var b=[0,0,0,0]
for i in 0..<4{
i%2==0 ? (a[i] += 1) : (b[i] += 1)
}
print(a)
print(b)
Result A=[1,0,1,0] B = [0,1,0,1]
You could use a function with an inout parameter:
func modify(g: inout [Int], index: Int) {
g[index] += 1
// 10 more lines of code about array g
}
var a = [0,0,0,0]
var b = [0,0,0,0]
for i in 0..<4 {
if i.isMultiple(of: 2) {
modify(g: &a, index: i)
} else {
modify(g: &b, index: i)
}
}
print(a)
print(b)
You could also put the arrays into a class (reference type) and use that reference to access the array instead of trying to reference the arrays (value types) directly.
See inout documentation here
Some info on value vs reference types
You are not "thinking value type", yet. For those, copy, modify, and reassign.
var array: [Int] { .init(repeating: 0, count: 4) }
let (a, b) = array.indices.reduce( into: (array, array) ) { arrays, index in
let indexIsEven = index.isMultiple(of: 2)
// Copy
var array = indexIsEven ? arrays.0 : arrays.1
// Modify
array[index] = 1
// Reassign
indexIsEven
? (arrays.0 = array)
: (arrays.1 = array)
}
Related
I am looking for a way to change the values of multiple variables using iteration in Swift. An example would be something like this:
var a = false
var b = false
var c = false
func makeAllTrue() {
for n in [a, b, c] {
n = true
}
}
...but rather than an array of values, I want to iterate through an array of pointers/references to the variables above.
Any advice would be greatly appreciated.
var a = false
var b = false
var c = false
mutateValues(&a, &b, &c) { n in
n = true
}
print(a, b, c) // will be printed "true true true"
func mutateValues<Value>(_ values: UnsafeMutablePointer<Value>..., mutate: (inout Value) -> Void) {
values.forEach {
mutate(&$0.pointee)
}
}
It is possible to do this with key paths. Let's say the properties are in a class Foo:
class Foo {
var a = false
var b = false
var c = false
func makeAllTrue() {
for n in [\Foo.a, \Foo.b, \Foo.c] {
self[keyPath: n] = true
}
}
}
If Foo is a struct, use mutating func instead:
struct Foo {
var a = false
var b = false
var c = false
mutating func makeAllTrue() {
for n in [\Foo.a, \Foo.b, \Foo.c] {
self[keyPath: n] = true
}
}
}
However, if the class name is long, I don't think it is worth doing this way.
If these three properties are very related, I would not bother with the key path stuff and replace a, b and c with an array:
var abc = [false, false, false]
and have the for loop loop over the indices:
for i in abc.indices {
abc[i] = true
}
An Array in Swift is a struct, hence a value type.
Iterating over his children, and changing one, will not be possible unless:
The type of child is aa class (which is reference typed)
You iterate over the indices and change the real values!
E.G:
var a: Int = 1
var b: Int = 2
var array: [Int] = [a,b]
for index in array.indices {
array[index] += 1
}
print(array) // [2,3]
I am trying to reference to an array inside a function.
Something like this: a and b are arrays of Ints.
var inout refArr = &a
if(!someFlag) {
refArr = &b
}
refArr[someIndex] = 30
This does not compile, can I only use inout for function arguments?
If so, how do I do a reference/pointer inside a function?
& can only be used to pass a variable as an inout argument to a function. So the easiest solution is perhaps to use a helper function
inside your function:
func foo() {
func helper(inout array : [Int]) {
array[2] = 99
}
var a = [1, 2, 3, 5, 6]
var b = [4, 5, 6, 7]
let someFlag = true
if someFlag {
helper(&a)
} else {
helper(&b)
}
// ...
}
You can create a reference to the array using UnsafeMutableBufferPointer:
let ref = someFlag ?
UnsafeMutableBufferPointer(start: &a, count: a.count) :
UnsafeMutableBufferPointer(start: &b, count: b.count)
ref[2] = 99
But there are two problems with this solution:
UnsafeMutableBufferPointer() creates a non-owning reference,
so the compiler might decide to deallocate the array while the reference
is still used.
There is no bounds check on the array.
So to make this work safely, you have to add some code:
withExtendedLifetime(a) { () -> Void in
withExtendedLifetime(b) { () -> Void in
let ref = someFlag ?
UnsafeMutableBufferPointer(start: &a, count: a.count) :
UnsafeMutableBufferPointer(start: &b, count: b.count)
if ref.count > 2 {
ref[2] = 99
}
}
}
which is a bit ugly.
You can use inout parameters in your function to accomplish this. Use the inout modifier for your parameters and use the ampersand (&) when passing a value into the function like so:
func swapTwoInts(inout a: Int, inout b: Int) {
let temporaryA = a
a = b
b = temporaryA
}
var x = 5
var y = 10
swapTwoInts(&x, &y)
x // 10
y // 5
Arrays in swift are not guaranteed to be contiguous in memory the way they are in C, so to insure you have access to a contiguous block, you have to either pass them to a function with an inout parameter or--if you really want a reference to an array within the function--create an UnsafeMutableBufferPointer like this[1]:
var someFlag: Bool = false
var a = ["a", "b", "c"]
var b = ["d", "e", "f"]
var refArr = a.withUnsafeMutableBufferPointer { (inout output: UnsafeMutableBufferPointer<String>) -> UnsafeMutableBufferPointer<String> in
return output
}
println(refArr[1]) //Will Output 'a'
if !someFlag {
refArr = b.withUnsafeMutableBufferPointer { (inout output: UnsafeMutableBufferPointer<String>) -> UnsafeMutableBufferPointer<String> in
return output
}
}
println(refArr[1]) //Will Output 'e'
1. Thread Safety with Swift Arrays
One can filter an array like this in swift:
var numbers = Array(1...1000000)
numbers = numbers.filter( { return $0 % 2 == 0 } )
Is it possible to filter and avoid the copy operation, that occurs when the filtering is done, e.g mutating the original array.
In a similar way to this pseudocode:
numbers.MutablefilterOperation({ return $0 % 2 == 0})
In C++ the equvivalent to what is going on in Swift above would be:
std::vector<int> originalNumbers(1000000);
std::vector<int> newNumbers;
std::copy_if (originalNumbers.begin(), originalNumbers.end(), std::back_inserter(newNumbers), [](int i) { return i % 2 == 0 } );
What I would like to achieve for performance reasons:
std::vector<int> originalNumbers(1000000);
auto pos = std::remove_if(originalNumbers.begin(), originalNumbers.end(), [](int x) { return x % 2 == 0; });
originalNumbers.erase(pos, originalNumbers.end());
This implementation should do the filtering without having to make a temporary copy of the entire array in the process (unless a copy of it is referenced by another variable, see "Copy on Write")
extension Array {
mutating func filterInPlace(isIncluded: (Element) throws -> Bool) rethrows {
var writeIndex = self.startIndex
for readIndex in self.indices {
let element = self[readIndex]
let include = try isIncluded(element)
if include {
if writeIndex != readIndex {
self[writeIndex] = element
}
writeIndex = self.index(after: writeIndex)
}
}
self.removeLast(self.distance(from: writeIndex, to: self.endIndex))
}
}
// example:
var arr = [6,2,6,5,2,5,6,2,2,1,6,7,3]
arr.filterInPlace { $0 % 2 == 1 }
print(arr) // [5, 5, 1, 7, 3]
What woudl be a simple way to reduce a string like AAA:111;BBB:222;333;444;CCC:555 to a dictionary in Swift. I have the following code:
var str = "AAA:111;BBB:222;333;444;CCC:555"
var astr = str.componentsSeparatedByString(";").map { (element) -> [String:String] in
var elements = element.componentsSeparatedByString(":")
if elements.count < 2 {
elements.insert("N/A", atIndex: 0)
}
return [elements[0]:elements[1]]
}
The code above produces an Array of Dictionaries:
[["A": "111"], ["BBB": "222"], ["UKW": "333"], ["UKW": "444"], ["CCC": "555"]]
I want it to produce
["A": "111", "BBB": "222", "UKW": "333", "UKW": "444", "CCC": "555"]
but no mater what I try, since i call the map function on an Array it seems impossible to convert the nature of the map function's result.
NOTE: The dictionary in string format is described as either having KEY:VALUE; format or VALUE; format, in which case the mapping function will add the "N/A" as being the key of the unnamed value.
Any help on this matter is greatly appreciated.
Your map produces an array of dictionaries. When you want to combine them into 1, that's a perfect job for reduce:
func + <K,V>(lhs: Dictionary<K,V>, rhs: Dictionary<K,V>) -> Dictionary<K,V> {
var result = Dictionary<K,V>()
for (key, value) in lhs {
result[key] = value
}
for (key, value) in rhs {
result[key] = value
}
return result
}
var str = "AAA:111;BBB:222;333;444;CCC:555"
var astr = str
.componentsSeparatedByString(";")
.reduce([String: String]()) {
aggregate, element in
var elements = element.componentsSeparatedByString(":")
if elements.count < 2 {
elements.insert("N/A", atIndex: 0)
}
return aggregate + [elements[0]:elements[1]]
}
print(astr)
Swift has no default operator to "combine" two Dictionaries so you have to define one. Note that the + here is not commutative: dictA + dictB != dictB + dictA. If a key exist in both dictionaries, the value from the second dictionary will be used.
This is a work for reduce:
let str = "AAA:111;BBB:222;333;444;CCC:555"
let keyValueStrings = str.componentsSeparatedByString(";")
let dictionary = keyValueStrings.reduce([String: String]()) {
aggregate, element in
var newAggregate = aggregate
let elements = element.componentsSeparatedByString(":")
let key = elements[0]
// replace nil with the value you want to use if there is no value
let value = (elements.count > 1) ? elements[1] : nil
newAggregate[key] = value
return newAggregate
}
print(dictionary)
You can also make aggregate mutable directly:
let dictionary = keyValueStrings.reduce([String: String]()) {
(var aggregate: [String: String], element: String) -> [String: String] in
let elements = element.componentsSeparatedByString(":")
let key = elements[0]
// replace nil with the value you want to use if there is no value
let value = (elements.count > 1) ? elements[1] : nil
aggregate[key] = value
return aggregate
}
This is a functional approach, but you can achieve the same using a for iteration.
The reason this is happening is because map can only return arrays. If you are using this method to parse your string, then you need to convert it to a dictionary after.
var newDict = [String:String]()
for x in astr {
for (i, j) in x {
newDict[i] = j
}
}
The current issue with your code is that map function iterates over array containing [["key:value"],["key:value"]..] and you separate it again. But it returns ["key":"value"] which you then add to your array.
Instead you can add elements[0]:elements[1] directly to a locally kept variable which will fix your problem. Something like
finalVariable[elements[0]] = elements[1]
Suppose I have an array and I want to pick one element at random.
What would be the simplest way to do this?
The obvious way would be array[random index]. But perhaps there is something like ruby's array.sample? Or if not could such a method be created by using an extension?
Swift 4.2 and above
The new recommended approach is a built-in method on the Collection protocol: randomElement(). It returns an optional to avoid the empty case I assumed against previously.
let array = ["Frodo", "Samwise", "Merry", "Pippin"]
print(array.randomElement()!) // Using ! knowing I have array.count > 0
If you don't create the array and aren't guaranteed count > 0, you should do something like:
if let randomElement = array.randomElement() {
print(randomElement)
}
Swift 4.1 and below
Just to answer your question, you can do this to achieve random array selection:
let array = ["Frodo", "Samwise", "Merry", "Pippin"]
let randomIndex = Int(arc4random_uniform(UInt32(array.count)))
print(array[randomIndex])
The castings are ugly, but I believe they're required unless someone else has another way.
Riffing on what Lucas said, you could create an extension to the Array class like this:
extension Array {
func randomItem() -> Element? {
if isEmpty { return nil }
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
For example:
let myArray = [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16]
let myItem = myArray.randomItem() // Note: myItem is an Optional<Int>
Swift 4 version:
extension Collection where Index == Int {
/**
Picks a random element of the collection.
- returns: A random element of the collection.
*/
func randomElement() -> Iterator.Element? {
return isEmpty ? nil : self[Int(arc4random_uniform(UInt32(endIndex)))]
}
}
In Swift 2.2 this can be generalised so that we have:
UInt.random
UInt8.random
UInt16.random
UInt32.random
UInt64.random
UIntMax.random
// closed intervals:
(-3...3).random
(Int.min...Int.max).random
// and collections, which return optionals since they can be empty:
(1..<4).sample
[1,2,3].sample
"abc".characters.sample
["a": 1, "b": 2, "c": 3].sample
First, implementing static random property for UnsignedIntegerTypes:
import Darwin
func sizeof <T> (_: () -> T) -> Int { // sizeof return type without calling
return sizeof(T.self)
}
let ARC4Foot: Int = sizeof(arc4random)
extension UnsignedIntegerType {
static var max: Self { // sadly `max` is not required by the protocol
return ~0
}
static var random: Self {
let foot = sizeof(Self)
guard foot > ARC4Foot else {
return numericCast(arc4random() & numericCast(max))
}
var r = UIntMax(arc4random())
for i in 1..<(foot / ARC4Foot) {
r |= UIntMax(arc4random()) << UIntMax(8 * ARC4Foot * i)
}
return numericCast(r)
}
}
Then, for ClosedIntervals with UnsignedIntegerType bounds:
extension ClosedInterval where Bound : UnsignedIntegerType {
var random: Bound {
guard start > 0 || end < Bound.max else { return Bound.random }
return start + (Bound.random % (end - start + 1))
}
}
Then (a little more involved), for ClosedIntervals with SignedIntegerType bounds (using helper methods described further below):
extension ClosedInterval where Bound : SignedIntegerType {
var random: Bound {
let foot = sizeof(Bound)
let distance = start.unsignedDistanceTo(end)
guard foot > 4 else { // optimisation: use UInt32.random if sufficient
let off: UInt32
if distance < numericCast(UInt32.max) {
off = UInt32.random % numericCast(distance + 1)
} else {
off = UInt32.random
}
return numericCast(start.toIntMax() + numericCast(off))
}
guard distance < UIntMax.max else {
return numericCast(IntMax(bitPattern: UIntMax.random))
}
let off = UIntMax.random % (distance + 1)
let x = (off + start.unsignedDistanceFromMin).plusMinIntMax
return numericCast(x)
}
}
... where unsignedDistanceTo, unsignedDistanceFromMin and plusMinIntMax helper methods can be implemented as follows:
extension SignedIntegerType {
func unsignedDistanceTo(other: Self) -> UIntMax {
let _self = self.toIntMax()
let other = other.toIntMax()
let (start, end) = _self < other ? (_self, other) : (other, _self)
if start == IntMax.min && end == IntMax.max {
return UIntMax.max
}
if start < 0 && end >= 0 {
let s = start == IntMax.min ? UIntMax(Int.max) + 1 : UIntMax(-start)
return s + UIntMax(end)
}
return UIntMax(end - start)
}
var unsignedDistanceFromMin: UIntMax {
return IntMax.min.unsignedDistanceTo(self.toIntMax())
}
}
extension UIntMax {
var plusMinIntMax: IntMax {
if self > UIntMax(IntMax.max) { return IntMax(self - UIntMax(IntMax.max) - 1) }
else { return IntMax.min + IntMax(self) }
}
}
Finally, for all collections where Index.Distance == Int:
extension CollectionType where Index.Distance == Int {
var sample: Generator.Element? {
if isEmpty { return nil }
let end = UInt(count) - 1
let add = (0...end).random
let idx = startIndex.advancedBy(Int(add))
return self[idx]
}
}
... which can be optimised a little for integer Ranges:
extension Range where Element : SignedIntegerType {
var sample: Element? {
guard startIndex < endIndex else { return nil }
let i: ClosedInterval = startIndex...endIndex.predecessor()
return i.random
}
}
extension Range where Element : UnsignedIntegerType {
var sample: Element? {
guard startIndex < endIndex else { return nil }
let i: ClosedInterval = startIndex...endIndex.predecessor()
return i.random
}
}
You can use Swift's built-in random() function as well for the extension:
extension Array {
func sample() -> Element {
let randomIndex = Int(rand()) % count
return self[randomIndex]
}
}
let array = [1, 2, 3, 4]
array.sample() // 2
array.sample() // 2
array.sample() // 3
array.sample() // 3
array.sample() // 1
array.sample() // 1
array.sample() // 3
array.sample() // 1
Another Swift 3 suggestion
private extension Array {
var randomElement: Element {
let index = Int(arc4random_uniform(UInt32(count)))
return self[index]
}
}
Following others answer but with Swift 2 support.
Swift 1.x
extension Array {
func sample() -> T {
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
Swift 2.x
extension Array {
func sample() -> Element {
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
E.g.:
let arr = [2, 3, 5, 7, 9, 11, 13, 17, 19, 23, 29, 31]
let randomSample = arr.sample()
An alternative functional implementation with check for empty array.
func randomArrayItem<T>(array: [T]) -> T? {
if array.isEmpty { return nil }
let randomIndex = Int(arc4random_uniform(UInt32(array.count)))
return array[randomIndex]
}
randomArrayItem([1,2,3])
Here's an extension on Arrays with an empty array check for more safety:
extension Array {
func sample() -> Element? {
if self.isEmpty { return nil }
let randomInt = Int(arc4random_uniform(UInt32(self.count)))
return self[randomInt]
}
}
You can use it as simple as this:
let digits = Array(0...9)
digits.sample() // => 6
If you prefer a Framework that also has some more handy features then checkout HandySwift. You can add it to your project via Carthage then use it exactly like in the example above:
import HandySwift
let digits = Array(0...9)
digits.sample() // => 8
Additionally it also includes an option to get multiple random elements at once:
digits.sample(size: 3) // => [8, 0, 7]
Swift 3
import GameKit
func getRandomMessage() -> String {
let messages = ["one", "two", "three"]
let randomNumber = GKRandomSource.sharedRandom().nextInt(upperBound: messages.count)
return messages[randomNumber].description
}
Swift 3 - simple easy to use.
Create Array
var arrayOfColors = [UIColor.red, UIColor.yellow, UIColor.orange, UIColor.green]
Create Random Color
let randomColor = arc4random() % UInt32(arrayOfColors.count)
Set that color to your object
your item = arrayOfColors[Int(randomColor)]
Here is an example from a SpriteKit project updating a SKLabelNode with a random String:
let array = ["one","two","three","four","five"]
let randomNumber = arc4random() % UInt32(array.count)
let labelNode = SKLabelNode(text: array[Int(randomNumber)])
If you want to be able to get more than one random element out of your array with no duplicates, GameplayKit has you covered:
import GameplayKit
let array = ["one", "two", "three", "four"]
let shuffled = GKMersenneTwisterRandomSource.sharedRandom().arrayByShufflingObjects(in: array)
let firstRandom = shuffled[0]
let secondRandom = shuffled[1]
You have a couple choices for randomness, see GKRandomSource:
The GKARC4RandomSource class uses an algorithm similar to that employed in arc4random family of C functions. (However, instances of this class are independent from calls to the arc4random functions.)
The GKLinearCongruentialRandomSource class uses an algorithm that is faster, but less random, than the GKARC4RandomSource class. (Specifically, the low bits of generated numbers repeat more often than the high bits.) Use this source when performance is more important than robust unpredictability.
The GKMersenneTwisterRandomSource class uses an algorithm that is slower, but more random, than the GKARC4RandomSource class. Use this source when itβs important that your use of random numbers not show repeating patterns and performance is of less concern.
I find using GameKit's GKRandomSource.sharedRandom() works best for me.
import GameKit
let array = ["random1", "random2", "random3"]
func getRandomIndex() -> Int {
let randomNumber = GKRandomSource.sharedRandom().nextIntWithUpperBound(array.count)
return randomNumber
or you could return the object at the random index selected. Make sure the function returns a String first, and then return the index of the array.
return array[randomNumber]
Short and to the point.
There is a built-in method on Collection now:
let foods = ["π", "π", "π£", "π"]
let myDinner = foods.randomElement()
If you want to extract up to n random elements from a collection you can add an extension like this one:
extension Collection {
func randomElements(_ count: Int) -> [Element] {
var shuffledIterator = shuffled().makeIterator()
return (0..<count).compactMap { _ in shuffledIterator.next() }
}
}
And if you want them to be unique you can use a Set, but the elements of the collection must conform to the Hashable protocol:
extension Collection where Element: Hashable {
func randomUniqueElements(_ count: Int) -> [Element] {
var shuffledIterator = Set(shuffled()).makeIterator()
return (0..<count).compactMap { _ in shuffledIterator.next() }
}
}
Latest swift3 code try it its working fine
let imagesArray = ["image1.png","image2.png","image3.png","image4.png"]
var randomNum: UInt32 = 0
randomNum = arc4random_uniform(UInt32(imagesArray.count))
wheelBackgroundImageView.image = UIImage(named: imagesArray[Int(randomNum)])
I figured out a very different way to do so using the new features introduced in Swift 4.2.
// ππΌ - 1
public func shufflePrintArray(ArrayOfStrings: [String]) -> String {
// - 2
let strings = ArrayOfStrings
//- 3
var stringans = strings.shuffled()
// - 4
var countS = Int.random(in: 0..<strings.count)
// - 5
return stringans[countS]
}
we declared a function with parameters taking an array of Strings and returning a String.
Then we take the ArrayOfStrings in a variable.
Then we call the shuffled function and store that in a variable. (Only supported in 4.2)
Then we declare a variable which saves a shuffled value of total count of the String.
Lastly we return the shuffled string at the index value of countS.
It is basically shuffling the array of strings and then also have a random pick of number of the total number of count and then returning the random index of the shuffled array.