Reputation: 27211
I want to retrieve a random emoji inside the range.
let emojiRanges = [
0x1F601...0x1F64F,
0x1F680...0x1F6C0,
]
let flattenEmoji = emojiRanges.flatten()
// the loop for emoji works
for i in flattenEmoji {
let st = String(format:"0x%2X %@", i, String(UnicodeScalar(i)))
print(st)
}
// but this is not possible to obtain value at wanted index
//there is a compiler error:
let randomSign = String(UnicodeScalar(flattenEmoji[arc4random_uniform(UInt32(flattenEmoji.count))]))
print("RANDOM \(randomSign)")
the error:
ViewController.swift:68:67: Cannot subscript a value of type 'FlattenBidirectionalCollection<[Range]>' (aka 'FlattenBidirectionalCollection>>') with an index of type 'UInt32'
What is the proper way to get a result?
Upvotes: 9
Views: 790
Reputation: 80811
The problem is that flatten()
is lazily applied, and therefore returns a special FlattenBidirectionalCollection
, which is indexed by a FlattenBidirectionalCollectionIndex
, rather than an Int
.
The simplest solution therefore would be to simply use the Array(_:)
constructor (or flatMap(_:)
) in order to eagerly apply the flattening of the ranges, which will create an array that you can then subscript with an Int
.
let flattenEmoji = Array(emojiRanges.flatten()) // In Swift 3, flatten() is named joined()
let randomIndex = Int(arc4random_uniform(UInt32(flattenEmoji.count)))
let randomSign = String(UnicodeScalar(flattenEmoji[randomIndex]))
If you wish to keep the flattening being lazily applied, you could subscript the FlattenBidirectionalCollection
directly (for Swift 2) through using advancedBy(_:)
on the collection's startIndex
:
let randomIndex = flattenEmoji.startIndex.advancedBy(Int(arc4random_uniform(UInt32(flattenEmoji.count))))
let randomSign = String(UnicodeScalar(flattenEmoji[randomIndex]))
In Swift 3, as collections move their indices, you'd want use the collection's index(_:offsetBy:)
method instead:
let randomIndex = flattenEmoji.index(flattenEmoji.startIndex, offsetBy: Int(arc4random_uniform(UInt32(flattenEmoji.count))))
Upvotes: 8
Reputation: 6114
Change emojiRanges
declaration to this:
let emojiRanges = Array(0x1F601...0x1F64F) + Array(0x1F680...0x1F6C0)
then life will become much easier.
for i in emojiRanges {
let st = String(format:"0x%2X %@", i, String(UnicodeScalar(i)))
print(st)
}
in randomSign
you should convert index to Int
let randomSign = String(UnicodeScalar(emojiRanges[Int(arc4random_uniform(UInt32(emojiRanges.count)))]))
print("RANDOM \(randomSign)")
Upvotes: 4