how to convert Range to Array
I tried:
let min = 50
let max = 100
let intArray:[Int] = (min...max)
get error Range<Int> is not convertible to [Int]
I also tried:
let intArray:[Int] = [min...max]
and
let intArray:[Int] = (min...max) as [Int]
they don't work either.
You need to create an Array<Int> using the Range<Int> rather than casting it.
let intArray: [Int] = Array(min...max)
Put the Range in the init.
let intArray = [Int](min...max)
I figured it out:
let intArray = [Int](min...max)
Giving credit to someone else.
do:
let intArray = Array(min...max)
This should work because Array has an initializer taking a SequenceType and Range conforms to SequenceType.
Use map
let min = 50
let max = 100
let intArray = (min...max).map{$0}
Interesting that you cannot (at least, with Swift 3 and Xcode 8) use Range<Int> object directly:
let range: Range<Int> = 1...10
let array: [Int] = Array(range) // Error: "doesn't conform to expected type 'Sequence'"
Therefore, as it was mentioned earlier, you need to manually "unwrap" you range like:
let array: [Int] = Array(range.lowerBound...range.upperBound)
I.e., you can use literal only.
Since Swift 3/Xcode 8 there is a CountableRange type, which can be handy:
let range: CountableRange<Int> = -10..<10
let array = Array(range)
print(array)
// prints:
// [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
It can be used directly in for-in loops:
for i in range {
print(i)
}
You can implement ClosedRange & Range instance intervals with reduce() in functions like this.
func sumClosedRange(_ n: ClosedRange<Int>) -> Int {
return n.reduce(0, +)
}
sumClosedRange(1...10) // 55
func sumRange(_ n: Range<Int>) -> Int {
return n.reduce(0, +)
}
sumRange(1..<11) // 55
Related
Hi I'm trying to learn Swift using Apples Fundamentals of Swift book.
There has been a similar post in the past but I have some problems with the answer provided that I would like clarified.
The post was Functions and optionals exercise
I'm on this exercise where you are supposed to print the return value. The return value being either nil if the stock of the item is 0 or the price if the stock is not 0. To add I thought the point was to unwrap the price value if you return it instead of nil. In earlier exercises they had us unwrap the optionals.
var prices = ["Chips": 2.99, "Donuts": 1.89, "Juice": 3.99, "Apple": 0.50, "Banana": 0.25, "Broccoli": 0.99]
var stock = ["Chips": 4, "Donuts": 0, "Juice": 12, "Apple": 6, "Banana": 6, "Broccoli": 3]
var prices = ["Chips": 2.99, "Donuts": 1.89, "Juice": 3.99, "Apple": 0.50, "Banana": 0.25, "Broccoli": 0.99]
var stock = ["Chips": 4, "Donuts": 0, "Juice": 12, "Apple": 6, "Banana": 6, "Broccoli": 3]
func purchase(item: String) -> Double? {
stock[item]! == 0 ? nil : prices[item]
}
print(purchase(item: "Chips"))
If I print(purchases(item: "Chips") I get printed optional(2.99). If it was unwrapped wouldn't it just be 2.99? I could cheat when I call the function and force unwrap but that ruins the point.
When I do try to safely unwrap I get a message saying "Missing return in a function expected to return 'Double?'"
As so:
var prices = ["Chips": 2.99, "Donuts": 1.89, "Juice": 3.99, "Apple": 0.50, "Banana": 0.25, "Broccoli": 0.99]
var stock = ["Chips": 4, "Donuts": 0, "Juice": 12, "Apple": 6, "Banana": 6, "Broccoli": 3]
func purchase(item: String) -> Double? {
if stock[item]! == 0 {
return nil
} else {
if let itemPrice = prices[item] {
return itemPrice
}
}
}
I could add another else return nil after the if let statement but then I'm back to having a wrapped optional.
Thanks for any answers
There are many ways to unwrap a value. You can try these ways.
1. The first way:
guard let value = purchase(item: "Chips") else { return }
print(value)
2. The second way:
if let value = purchase(item: "Chips"){
print(value)
}
3. The third way:
if (purchase(item: "Chips") != nil){
print(purchase(item: "Chips")!)
}
You can't unwrap in the function. The function returns an optional; that is the specification you are given.
Since the function returns an optional, you can't simply print the return value (well, you can, but you get "optional(2.99)" ).
First, you can re-write your function to avoid force unwrapping (the specification says that you should pass a string that is in the dictionary, but it is always a good to code defensively).
func purchase(item: String) -> Double? {
if let qty = stock[item], qty > 0, price = prices[item] {
return price
}
return nil
}
Then you can use the function
if let price = purchase("chips") {
print("Purchased for $\(price)")
} else {
print("None in stock")
}
My Task:
I need to divide the Array into several Arrays of Arrays with the following properties:
every subarray is a range of continuous integer. As example [1,2,3,4,5] will be [[1,5]].
When there are no contiguous integer create a new subarray. As example [1,2,4,5] will be [[1,2], [4,5]]
Example:
If I have this Array of Integers - [0, 1, 5, 6, 3, 7]
Expected Result - [[0, 1], [3], [5, 7]]
I already tried this:
let array: [Int] = [0, 1, 3, 4, 5, 6, 7]
var group: [[Int]] = []
var temp: [Int] = [Int]()
for (index, element) in array.enumerated() {
if index + 1 < array.count {
let nextElement = array[index + 1]
let step = nextElement - element
// temp.append(element)
if(step) == 1 { // Until it's in range
temp.append(element)
} else { // One-by-one
temp.append(element)
group.append(temp)
temp = [Int]()
group.append([nextElement])
}
} else {
print(index)
}
}
print(group)
From my code, I get this result - [[0, 1], [3]]
There is an API, IndexSet:
It's not clear what you want, your examples are ambiguous.
If you want an array of ranges
let indexSet = IndexSet(array)
let rangeView = indexSet.rangeView
let group = rangeView.map { $0.indices.startIndex..<$0.indices.endIndex }
If you want a grouped array by ranges
let indexSet = IndexSet(array)
let rangeView = indexSet.rangeView
let group = rangeView.map { Array($0.indices) }
This is the best approach I found:
let array: [Int] = [0, 1, 5, 6, 3, 7].sorted();
var group: [[Int]] = []
var temp: [Int] = [Int]()
var lastElement: Int = -1;
for (index, element) in array.enumerated() {
if lastElement == -1 {
temp.append(element);
}
else {
if element - lastElement == 1 {
temp.append(element);
}
else {
group.append(temp);
temp = [Int]();
temp.append(element);
}
}
lastElement = element;
}
if temp.count > 0 {
group.append(temp);
}
print(group)
Here is my solution. Rather than manually managing indexes, I use two iterators. One which advances along denoting the "start" of runs, and one which races ahead to find the "ends" of runs.
I've gentrified my code to work over any Sequence (not just Array), and any Strideable type (any type that defines distance(to:), not necessarily just Int).
extension Sequence where Element: Strideable {
func splitConsequtiveRuns() -> [[Element]] {
var runs = [[Element]]()
var runStartIterator = self.makeIterator()
while let startElement = runStartIterator.next() {
var runEndIterator = runStartIterator
var prevElement = startElement
var run = [startElement]
while let nextElement = runEndIterator.next(),
prevElement.distance(to: nextElement) == 1 {
_ = runStartIterator.next() // advance the "start" iterator, to keep pace
prevElement = nextElement // update this, for use in then next loop's comparison
run.append(nextElement)
}
runs.append(run)
}
return runs
}
}
let array: [Int] = [0...3, 8...8, 10...15].flatMap { $0 }
print(array.splitConsequtiveRuns()) // => [[0, 1, 2, 3], [8], [10, 11, 12, 13, 14, 15]]
i want to use arc4random but produced Numbers are must different each other.
How do i do this example?
How about this:
let desired = 20
var randomSet: Set<Int> = [] //Sets guarantee uniqueness
var array: [Int] = [] //Use arrays to guarantee the order
while array.count < desired {
let random = Int(arc4random())
if !randomSet.contains(random) {
array.append(random)
randomSet.insert(random)
}
}
Or, using LeoDaubus' suggestion:
while array.count < desired {
let random = Int(arc4random())
if randomSet.insert(random).inserted {
array.append(random)
}
}
You can use Set to easily achieve this:
var randomSet: Set<Int> = [] //Sets guarantee uniqueness
var array: [Int] = [] //Use arrays to guarantee the order
while randomSet.count < 2 {
randomSet.insert(Int(arc4random())) //Whatever random number generator you use
}
for number in randomSet {
array.append(number)
}
//Now you can use the array for your operations
You can use a set to check if the random number was inserted appending the member after checking if it was inserted:
var set: Set<Int> = []
var randomElements: [Int] = []
let numberOfElements = 10
while set.count < numberOfElements {
let random = Int(arc4random_uniform(10)) // 0...9
set.insert(random).inserted ? randomElements.append(random) : ()
}
print(randomElements) // "[5, 2, 8, 0, 7, 1, 4, 3, 6, 9]\n"
I'm trying to implement an image algorithm that iterates the byte array of the image.
(I'm trying to replicate this in Swift... https://rosettacode.org/wiki/Percentage_difference_between_images#JavaScript)
However, I need to ignore the alpha byte.
I was trying to be clever about it but got to the point where I can no longer remove the 4th items from the arrays of bytes.
Is there an easy way of doing that?
func compareImages(image1: UIImage, image2: UIImage) -> Double {
// get data from images
guard let data1 = UIImageJPEGRepresentation(image1, 1),
let data2 = UIImageJPEGRepresentation(image2, 1) else {
return -1
}
// zip up byte arrays
return zip([UInt8](data1), [UInt8](data2))
// sum the difference of the bytes divided by 255
.reduce(0.0) { $0 + Double(abs(Int32($1.0) - Int32($1.1))) / 255.0 }
// divide by the number of rbg bytes
/ Double(image1.size.width * image1.size.height * 3)
}
This would do exactly what I needed if I was able to remove/ignore the 4th bytes from each array?
The other option is to stride the arrays 4 at a time like it does in the Javascript example linked to but I felt I preferred this method. :)
i think you can remove alpha with this
enumerate to get pair (index, element)
filter to remove alpha
map to convert pair to only element
example code:
var array = [0,1,2,3,4,5,6,7,8,9]
array = array.enumerated().filter { index, element in
return index % 4 != 3
}.map { index, element in
return element
}
print(array) // [0,1,2,4,5,6,8,9]
Swift 3:
var array = [0,1,2,3,4,5,6,7,8,9]
array = array.enumerated().flatMap { index, element in
index % 4 != 3 ? element : nil
}
print(array) // [0,1,2,4,5,6,8,9]
Image data can be large, therefore I would avoid creating
intermediate arrays only to remove each 4th element.
Your zip + reduce approach can be combined with enumerated()
so that every 4th byte is ignored in the summation:
func rgbdiff(data1: [UInt8], data2: [UInt8], width: Int, height: Int) -> Double {
return zip(data1, data2).enumerated().reduce(0.0) {
$1.offset % 4 == 3 ? $0 : $0 + abs(Double($1.element.0) - Double($1.element.1))/255.0
} / Double(width * height * 3)
}
Here it is assumed that data1 and data2 are arrays with the
RGBA pixel data and both images have the same dimensions.
You could also work on Data values without conversion to arrays:
func rgbdiff(data1: Data, data2: Data, width: Int, height: Int) -> Double {
// ... same function ...
}
because the Swift 3 Data is an Iterator of its bytes.
Another, just a little bit more swifty way.
var foo = [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
var bar = [Int]()
for i in stride(from: 0, to: foo.count - 3, by: 4) {
bar += foo[i..<i+3]
}
bar //[1, 2, 3, 1, 2, 3, 1, 2, 3]
OK, for anyone who wants an update on filtering the array but also getting the correct pixel data...
I used a version of the answer from here... Get pixel data as array from UIImage/CGImage in swift
And #MartinR's answer to create the following two functions...
func pixelValues(fromCGImage imageRef: CGImage?) -> [UInt8]?
{
var width = 0
var height = 0
var pixelValues: [UInt8]?
if let imageRef = imageRef {
width = imageRef.width
height = imageRef.height
let bitsPerComponent = imageRef.bitsPerComponent
let bytesPerRow = imageRef.bytesPerRow
let totalBytes = height * bytesPerRow
let bitmapInfo = imageRef.bitmapInfo
let colorSpace = CGColorSpaceCreateDeviceRGB()
var intensities = [UInt8](repeating: 0, count: totalBytes)
let contextRef = CGContext(data: &intensities, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
contextRef?.draw(imageRef, in: CGRect(x: 0.0, y: 0.0, width: CGFloat(width), height: CGFloat(height)))
pixelValues = intensities
}
return pixelValues
}
func compareImages(image1: UIImage, image2: UIImage) -> Double? {
guard let data1 = pixelValues(fromCGImage: image1.cgImage),
let data2 = pixelValues(fromCGImage: image2.cgImage),
data1.count == data2.count else {
return nil
}
let width = Double(image1.size.width)
let height = Double(image1.size.height)
return zip(data1, data2)
.enumerated()
.reduce(0.0) {
$1.offset % 4 == 3 ? $0 : $0 + abs(Double($1.element.0) - Double($1.element.1))
}
* 100 / (width * height * 3.0) / 255.0
}
I will be submitting this to the Rosetta website as soon as I work out how.
let array1 = [1, 2, 3, 255, 5, 6, 7, 255, 8, 9, 10, 255]
let array2 = [1, 2, 3, 0, 5, 6, 7, 0, 8, 9, 10, 0]
let difference = zip(array1, array2) // Make one sequence from two arrays
.enumerated() // Assign each pair an index
.filter({ $0.offset % 4 != 3 }) // Strip away each 4th pair
.map({ $0.element }) // Discard indices
.reduce(0, { $0 + Swift.abs($1.0 - $1.1) }) / 255 // Do the math
print(difference) // 0
Just make sure that both arrays have equal count of elements.
I'm just starting to learn Swift.
I'm attempting to create an array of several random numbers, and eventually sort the array. I'm able to create an array of one random number, but what's the best way to iterate this to create an array of several random numbers?
func makeList() {
var randomNums = arc4random_uniform(20) + 1
let numList = Array(arrayLiteral: randomNums)
}
makeList()
In Swift 4.2 there is a new static method for fixed width integers that makes the syntax more user friendly:
func makeList(_ n: Int) -> [Int] {
return (0..<n).map { _ in .random(in: 1...20) }
}
Edit/update: Swift 5.1 or later
We can also extend Range and ClosedRange and create a method to return n random elements:
extension RangeExpression where Bound: FixedWidthInteger {
func randomElements(_ n: Int) -> [Bound] {
precondition(n > 0)
switch self {
case let range as Range<Bound>: return (0..<n).map { _ in .random(in: range) }
case let range as ClosedRange<Bound>: return (0..<n).map { _ in .random(in: range) }
default: return []
}
}
}
extension Range where Bound: FixedWidthInteger {
var randomElement: Bound { .random(in: self) }
}
extension ClosedRange where Bound: FixedWidthInteger {
var randomElement: Bound { .random(in: self) }
}
Usage:
let randomElements = (1...20).randomElements(5) // [17, 16, 2, 15, 12]
randomElements.sorted() // [2, 12, 15, 16, 17]
let randomElement = (1...20).randomElement // 4 (note that the computed property returns a non-optional instead of the default method which returns an optional)
let randomElements = (0..<2).randomElements(5) // [1, 0, 1, 1, 1]
let randomElement = (0..<2).randomElement // 0
Note: for Swift 3, 4 and 4.1 and earlier click here.
Ok, this is copy/paste of a question asked elsewhere, but I think I'll try to remember that one-liner:
var randomArray = map(1...100){_ in arc4random()}
(I love it!)
If you need a random number with an upperBound (exclusive), use arc4random_uniform(upperBound).
E.g.: random number between 0 and 99: arc4random_uniform(100)
Swift 2 update
var randomArray = (1...100).map{_ in arc4random()}
Swift 5
This creates an array of size 5, and whose elements range from 1 to 10 inclusive.
let arr = (1...5).map( {_ in Int.random(in: 1...10)} )
Swift 4.2 or later
func makeList(_ n: Int) -> [Int] {
return (0..<n).map{ _ in Int.random(in: 1 ... 20) }
}
let list = makeList(5) //[11, 17, 20, 8, 3]
list.sorted() // [3, 8, 11, 17, 20]
How about this? Works in Swift 5 and Swift 4.2:
public extension Array where Element == Int {
static func generateRandom(size: Int) -> [Int] {
guard size > 0 else {
return [Int]()
}
return Array(0..<size).shuffled()
}
}
Usage:
let array = Array.generateRandom(size: 10)
print(array)
Prints e.g.:
[7, 6, 8, 4, 0, 3, 9, 2, 1, 5]
The above approach gives you unique numbers. However, if you need redundant values, use the following implementation:
public extension Array where Element == Int {
static func generateRandom(size: Int) -> [Int] {
guard size > 0 else {
return [Int]()
}
var result = Array(repeating: 0, count: size)
for index in 0..<result.count {
result[index] = Int.random(in: 0..<size)
}
return result
}
}
A shorter version of the above using map():
public extension Array where Element == Int {
static func generateRandom(size: Int) -> [Int] {
guard size > 0 else {
return [Int]()
}
var result = Array(repeating: 0, count: size)
return result.map{_ in Int.random(in: 0..<size)}
}
}