Count hashmap elements with condition for members? [duplicate] - arrays

I'm basically looking for the swift equivalent of the follow c++ code:
std::count_if(list.begin(), list.end(), [](int a){ return a % 2 == 0; }); // counts instances of even numbers in list
My problem isn't actually searching for even numbers, of course; simply the general case of counting instances matching a criterion.
I haven't seen a builtin, but would love to hear that I simply missed it.

Like this:
let a: [Int] = ...
let count = a.filter({ $0 % 2 == 0 }).count

An alternative to Aderstedt's version
let a = [ .... ]
let count = a.reduce(0){
(count, element) in
return count + 1 - element % 2
}
My intuition says my way will be faster because it doesn't require the creation of a second array. However, you'd need to profile both methods to be sure.
Edit
Following MartinR's comment about generalisation of the function, here it is
extension SequenceType
{
func countMatchingCondition(condition: (Self.Generator.Element) -> Bool) -> Int
{
return self.reduce(0, combine: { (count, e) in count + (condition(e) ? 1 : 0) })
}
}
let a = [1, 2, 3, 3, 4, 12].countMatchingCondition { $0 % 2 == 0 }
print("\(a)") // Prints 3

Default array:
let array: [Int] = [10, 10, 2, 10, 1, 2, 3]
filter(_:) method
let countOfTen = array.filter({ $0 == 10 }).count // 3
count(where:) method
Update: This Swift 5.0 feature was withdrawn in beta testing because it was causing performance issues for the type checker.
let countOfTen = array.count(where: { $0 == 10 }) // 3

You can use Collection.lazy to have the simplicity of Aderstedt's Answer but with O(1) space.
let array = [1, 2, 3]
let count = array.lazy.filter({ $0 % 2 == 0 }).count

The most compact reduce statement that will do this is:
let a = Array(1 ... 20)
let evencount = a.reduce(0) { $0 + ($1 % 2 == 0 ? 1 : 0) }
Reduce takes two variables: starts with 0 (var $0) then for every element in Array a (var $1) if the value is divisible by 2 with no remainder then add one to your count.
This is also efficient as it does not create an additional array unlike using a.filter(){}.count .

You can also do this with reduce()
let a = Array(1 ... 20)
let evenCount = a.reduce(0) { (accumulator, value) -> Int in
guard value % 2 == 0 else { return accumulator }
return accumulator + 1
}
Almost everything you want to do with the map() and filter functions can actually be done with a reduce although it's not always the most readable.

Swift 5 or later:
public extension Sequence {
func occurrences(where predicate: (Element) throws -> Bool) rethrows -> Int {
try reduce(0) { try predicate($1) ? $0 + 1 : $0 }
}
}
public extension Sequence where Element: Equatable {
func occurrences(of element: Element) -> Int {
reduce(0) { element == $1 ? $0 + 1 : $0 }
}
}
let multiplesOf2 = [1,2,3,4,4,5,4,5].occurrences{$0.isMultiple(of: 2)} // 4
"abcdeabca".occurrences(of: "a") // 3
extension BinaryInteger {
var isOdd: Bool { !isMultiple(of: 2) }
var isEven: Bool { isMultiple(of: 2) }
}
(-4).isOdd // false
(-3).isOdd // true
(-2).isOdd // false
(-1).isOdd // true
0.isOdd // false
1.isOdd // true
2.isOdd // false
3.isOdd // true
4.isOdd // false
(-4).isEven // true
(-3).isEven // false
(-2).isEven // true
(-1).isEven // false
0.isEven // true
1.isEven // false
2.isEven // true
3.isEven // false
4.isEven // true
let odds = [1,2,3,4,4,5,5,11].occurrences(where: \.isOdd) // 5
let evens = [1,2,3,4,4,5,5,11].occurrences(where: \.isEven) // 3

Related

Swift array remove consecutive numbers via filter

How it is possible to write filter function that will remove consecutive numbers from array.
By consecutive I mean 1,2,3,4 form a sequence contrary to 1,3,5 (missing the 2 and 5).
Example:
let input = [1,2,3,4,8,10,12,19]
//Expected filter function.
let output = [8,10,12,19]
You can use flatMap which acts as a map and a filter against nil:
let output = input.enumerated().flatMap { index, element in
return index > 0 && input[index - 1] + 1 == element ? nil : element
}
print(output) // [1, 8, 10, 12, 19]
let input = [1,2,3,4,8,10,12,19]
func filterConsecutive(array: [Int]) -> [Int] {
guard array.count > 1 else {
return array
}
var result = [Int]()
for i in 0...array.count-2 {
let first = array[i]
let second = array[i+1]
if second != first + 1 {
result.append(second)
}
}
return result
}
let result = filterConsecutive(array: input)

Getting the most frequent value of an array

I have an Array of numbers and I want to know which number is most frequent in this array. The array sometimes has 5-6 integers, sometimes it has 10-12, sometimes even more - also the integers in the array can be different. So I need a function which can work with different lengths and values of an array.
One example:
myArray = [0, 0, 0, 1, 1]
Another example:
myArray = [4, 4, 4, 3, 3, 3, 4, 6, 6, 5, 5, 2]
Now I am searching for a function which gives out 0 (in the first example) as Integer, as it is 3 times in this array and the other integer in the array (1) is only 2 times in the array. Or for the second example it would be 4.
It seems pretty simple, but I cannot find a solution for this. Found some examples in the web, where the solution is to work with dictionaries or where the solution is simple - but I cannot use it with Swift 3 it seems...
However, I did not find a solution which works for me. Someone has an idea how to get the most frequent integer in an array of integers?
You can also use the NSCountedSet, here's the code
let nums = [4, 4, 4, 3, 3, 3, 4, 6, 6, 5, 5, 2]
let countedSet = NSCountedSet(array: nums)
let mostFrequent = countedSet.max { countedSet.count(for: $0) < countedSet.count(for: $1) }
Thanks to #Ben Morrow for the smart suggestions in the comments below.
let myArray = [4, 4, 4, 3, 3, 3, 4, 6, 6, 5, 5, 2]
// Create dictionary to map value to count
var counts = [Int: Int]()
// Count the values with using forEach
myArray.forEach { counts[$0] = (counts[$0] ?? 0) + 1 }
// Find the most frequent value and its count with max(by:)
if let (value, count) = counts.max(by: {$0.1 < $1.1}) {
print("\(value) occurs \(count) times")
}
Output:
4 occurs 4 times
Here it is as a function:
func mostFrequent(array: [Int]) -> (value: Int, count: Int)? {
var counts = [Int: Int]()
array.forEach { counts[$0] = (counts[$0] ?? 0) + 1 }
if let (value, count) = counts.max(by: {$0.1 < $1.1}) {
return (value, count)
}
// array was empty
return nil
}
if let result = mostFrequent(array: [1, 3, 2, 1, 1, 4, 5]) {
print("\(result.value) occurs \(result.count) times")
}
1 occurs 3 times
Update for Swift 4:
Swift 4 introduces reduce(into:_:) and default values for array look ups which enable you to generate the frequencies in one efficient line. And we might as well make it generic and have it work for any type that is Hashable:
func mostFrequent<T: Hashable>(array: [T]) -> (value: T, count: Int)? {
let counts = array.reduce(into: [:]) { $0[$1, default: 0] += 1 }
if let (value, count) = counts.max(by: { $0.1 < $1.1 }) {
return (value, count)
}
// array was empty
return nil
}
if let result = mostFrequent(array: ["a", "b", "a", "c", "a", "b"]) {
print("\(result.value) occurs \(result.count) times")
}
a occurs 3 times
The most frequent value is called the "mode". Here's a concise version:
let mode = myArray.reduce([Int: Int]()) {
var counts = $0
counts[$1] = ($0[$1] ?? 0) + 1
return counts
}.max { $0.1 < $1.1 }?.0
Whether that's considered "unreadable" or "elegant" depends on your feelings towards higher order functions. Nonetheless, here it is as a generic method in an extension on Array (so it'll work with any Hashable element type):
extension Array where Element: Hashable {
var mode: Element? {
return self.reduce([Element: Int]()) {
var counts = $0
counts[$1] = ($0[$1] ?? 0) + 1
return counts
}.max { $0.1 < $1.1 }?.0
}
}
Simply remove the .0 if you'd rather have a tuple that includes the count of the mode.
My take on it with Swift 5:
extension Collection {
/**
Returns the most frequent element in the collection.
*/
func mostFrequent() -> Self.Element?
where Self.Element: Hashable {
let counts = self.reduce(into: [:]) {
return $0[$1, default: 0] += 1
}
return counts.max(by: { $0.1 < $1.1 })?.key
}
}
I have tried the following code. It helps especially when the max count is applicable for 2 or more values.
var dictionary = arr.reduce(into: [:]) { counts, number in counts[number, default: 0] += 1}
var max = dictionary.values.max()!
dictionary = dictionary.filter{$0.1 == max}
mode = dictionary.keys.min()!
func mostR(num : [Int]) -> (number : Int , totalRepeated : Int)
{
var numberTofind : Int = 0
var total : Int = 0
var dic : [Int : Int] = [:]
for index in num
{
if let count = dic[index]
{
dic[index] = count + 1
}
else
{
dic[index] = 1
}
}
var high = dic.values.max()
for (index , count) in dic
{
if dic[index] == high
{
numberTofind = index
top.append(count)
total = count
}
}
return (numberTofind , total)
}
var array = [1,22,33,55,4,3,2,0,0,0,0]
var result = mostR(num : [1,22,3,2,43,2,11,0,0,0])
print("the number is (result.number) and its repeated by :(result.totalRepeated)" )
Here is an encapsulated/reusable method.
extension Array where Element: Hashable {
/// The mode will be nil when the array is empty.
var mode: Element? {
var counts: [Element: Int] = [:]
forEach { counts[$0] = (counts[$0] ?? 0) + 1 }
if let (value, count) = counts.max(by: {$0.1 < $1.1}) {
print("\(value) occurs \(count) times")
return value
} else {
return nil
}
}
}
usage:
print([3, 4, 5, 6, 6].mode) // 6
Keep track of each occurrence, counting the value of each key in a dictionary. This case is exclusive for integers. Will update this method using generics.
func mostCommon(of arr: [Int]) -> Int {
var dict = [Int:Int]()
arr.forEach {
if let count = dict[$0] {
dict[$0] = count + 1
} else {
dict[$0] = 1
}
}
let max = dict.values.max()
for (_ , value) in dict {
if value == max {
return value
}
}
return -1
}

How to mutate an array of integers in-place in swift through filtering

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]

check if all elements of an array have the same value in Swift

Is there a function in Swift that checks whether all elements of an array have the same value? In my case, it's an array of type Int. I know I can iterate over it using a simple for loop I was just wondering if there is something that is built in and quicker.
With Swift 5, you can use one of the four following ways in order to tests if all elements of an array are equal.
#1. Using Array's allSatisfy(_:) method
allSatisfy(_:) returns a Boolean value indicating whether every element of a sequence satisfies a given predicate. You can set the predicate to test if all elements of the array are equal:
let array = [1, 1, 1]
let hasAllItemsEqual = array.dropFirst().allSatisfy({ $0 == array.first })
print(hasAllItemsEqual) // prints: true
let array = [1, 1, 3]
let hasAllItemsEqual = array.dropFirst().allSatisfy({ $0 == array.first })
print(hasAllItemsEqual) // prints: false
let array = [Int]()
let hasAllItemsEqual = array.dropFirst().allSatisfy({ $0 == array.first })
print(hasAllItemsEqual) // prints: true
#2. Using Array's reduce(_:_:) method
As an alternative to allSatisfy(_:), you can use reduce(_:_:):
let array = [1, 1, 1]
let hasAllItemsEqual = array.dropFirst().reduce(true) { (partialResult, element) in
return partialResult && element == array.first
}
print(hasAllItemsEqual) // prints: true
let array = [1, 1, 3]
let hasAllItemsEqual = array.dropFirst().reduce(true) { (partialResult, element) in
return partialResult && element == array.first
}
print(hasAllItemsEqual) // prints: false
let array = [Int]()
let hasAllItemsEqual = array.dropFirst().reduce(true) { (partialResult, element) in
return partialResult && element == array.first
}
print(hasAllItemsEqual) // prints: true
#3. Using elementsEqual(_:) method
elementsEqual(_:) returns a Boolean value indicating whether two sequences contain the same elements in the same order. Therefore you can create a new collection by repeating the first element of the initial array and compare the former with the latter:
let array = [1, 1, 1]
precondition(!array.isEmpty)
let repeated = repeatElement(array[0], count: array.count)
let hasAllItemsEqual = array.elementsEqual(repeated)
print(hasAllItemsEqual) // prints: true
let array = [1, 1, 3]
precondition(!array.isEmpty)
let repeated = repeatElement(array[0], count: array.count)
let hasAllItemsEqual = array.elementsEqual(repeated)
print(hasAllItemsEqual) // prints: false
#4. Using Set's init(_:) initalizer
If all elements of an array are equal, creating a set from this array should result in the set having only one element:
let array = [1, 1, 1]
let set = Set(array)
let hasAllItemsEqual = set.count <= 1
print(hasAllItemsEqual) // prints: true
let array = [1, 1, 3]
let set = Set(array)
let hasAllItemsEqual = set.count <= 1
print(hasAllItemsEqual) // prints: false
let array = [Int]()
let set = Set(array)
let hasAllItemsEqual = set.count <= 1
print(hasAllItemsEqual) // prints: true
Any method must iterate over all elements until a different element is found:
func allEqualUsingLoop<T : Equatable>(array : [T]) -> Bool {
if let firstElem = array.first {
for elem in array {
if elem != firstElem {
return false
}
}
}
return true
}
Instead of an explicit loop you can use the contains() function:
func allEqualUsingContains<T : Equatable>(array : [T]) -> Bool {
if let firstElem = array.first {
return !contains(array, { $0 != firstElem })
}
return true
}
If the array elements are Hashable (such as Int) then you can
create a Set (available since Swift 1.2) from the array elements and check if it has exactly one element.
func allEqualUsingSet<T : Hashable>(array : [T]) -> Bool {
let uniqueElements = Set(array)
return count(uniqueElements) <= 1
}
A quick benchmarking test revealed that the "contains" method is much faster than the "set" method
for an array of 1,000,000 integers, in particular if the elements are
not all equal. This make sense because contains() returns as soon
as a non-matching element is found, whereas Set(array) always
traverses the entire array.
Also the "contains" methods is equally fast or slightly faster than an explicit loop.
Here is some simple benchmarking code. Of course the results can vary
with the array size, the number of different elements and the elements data type.
func measureExecutionTime<T>(title: String, #noescape f : (() -> T) ) -> T {
let start = NSDate()
let result = f()
let end = NSDate()
let duration = end.timeIntervalSinceDate(start)
println("\(title) \(duration)")
return result
}
var array = [Int](count: 1_000_000, repeatedValue: 1)
array[500_000] = 2
let b1 = measureExecutionTime("using loop ") {
return allEqualUsingLoop(array)
}
let b2 = measureExecutionTime("using contains") {
allEqualUsingContains(array)
}
let b3 = measureExecutionTime("using set ") {
allEqualUsingSet(array)
}
Results (on a MacBook Pro, Release configuration):
using loop 0.000651001930236816
using contains 0.000567018985748291
using set 0.0344770550727844
With array[1_000] = 2 the results are
using loop 9.00030136108398e-06
using contains 2.02655792236328e-06
using set 0.0306439995765686
Update for Swift 2/Xcode 7: Due to various changes in the Swift
syntax, the function is now written as
func allEqual<T : Equatable>(array : [T]) -> Bool {
if let firstElem = array.first {
return !array.dropFirst().contains { $0 != firstElem }
}
return true
}
But you can now also define it as an extension method for arrays:
extension Array where Element : Equatable {
func allEqual() -> Bool {
if let firstElem = first {
return !dropFirst().contains { $0 != firstElem }
}
return true
}
}
print([1, 1, 1].allEqual()) // true
print([1, 2, 1].allEqual()) // false
Soliution for Swift 4.2/Xcode 10:
let arr = [1, 1, 1, 1]
let allItemsEqual = arr.dropLast().allSatisfy { $0 == arr.last }
print(allItemsEqual)
If your current version of Xcode is prior to 10.0 you can find the function allSatisfy of ArraySlice in Xcode9to10Preparation. You can install this library with CocoaPods.
let ints: [Int] = [1, 1, 1, 1]
print(ints.max() == ints.min())
If you have float buffers or if you already have an array of floats (or you think converting to floats beforehand is convenient):
import Accelerate
// [...]
// let floats = ints.map({ Double($0) })
print(vDSP.minimum(floats) == vDSP.maximum(floats))

How do I make this extension of Array? [duplicate]

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.

Resources