How to obtain three arrays containing three objects or less? - arrays

I want to obtain three arrays containing three objects or less. I have a class named Product and an array who have 9 products or less downloaded form Firebase, so I want to generate three arrays, each one will have three different products in order. This is what I have:
var products = [Product]()
products = [product1, product2, product3, product4, product5, product6, product7, product8, product9]
And this is what I want to obtain:
array1 = [product1, product2, product3]
array2 = [product4, product5, product6]
array3 = [product7, product8, product9]
In some cases the array named product will have a number of products less than 9 so I have to create those arrays automatically with 3 or less products.
I'm doing this because my code have to generate an array that has three arrays inside, each one with three products or less to show in a collection view inside a tableview [[Product]].

You can slice an array by using the [] operator with a range. Note that this returns a view into the original array, so if you want a copy you pass the slice to Array() to create a new copy:
let numbers:[Int] = stride(from: 1, to: 10, by: 1).map{$0}
print(numbers.count)
let first = Array(numbers[0...2])
let second = Array(numbers[3...5])
let third = Array(numbers[6...8])
print(first, second, third)
To convert an array of arbitrary length into a number of arrays with 3 elements or less:
let numbers:[Int] = stride(from: 1, to: 14, by: 1).map{$0}
var bins: [[Int]] = []
for index in stride(from: 0, to: numbers.count, by: 3) {
let endIndex = min(index + 2, numbers.count - 1)
bins.append(Array(numbers[index...endIndex]))
}
print(bins)

Gustavo expects the extra variables to contain empty arrays when there are fewer than 6 or 3 products.
this should do it:
let productsBy3 = (0..<3).map{ i in products.indices.filter{$0/3==i}.map{products[$0]}}

Related

How can I assign the values of one array to a multiple dimension array?

I am creating a multiple dimension array and I need to assign the column names to the array, but I keep getting the error:
Cannot convert the value of type String to expected argument of type
[String]
I am new to swift, so I don't really know what to do, so here is my code:
var data = [[[String]]]()
var rows = 3
var columns = 3
var column_names = ["Red", "Blue", "Green", "Orange"]
var index1 = 0
for index1 in 0...columns{
data[index1] = column_names[index1]
}
The code var data = [[[String]]]() creates an array of arrays of arrays. you need 3 indexes if you want to be able to insert a string into it.
Assuming you only want a 2-dimensional array, you might use code like this instead:
var data = [[String]]()
var column_names = ["Red", "Blue", "Green", "Orange"]
let rows = 3
let columns = column_names.count
let empty_row = Array(repeating: "", count: columns)
data.append(column_names)
for _ in 1 ..< rows {
data.append(empty_row)
}
print(data)
In the code above we create an empty 2 dimensional array. We then add an array of column names, followed by rows of empty strings.
Swift doesn't actually have a native n-dimensional array type. Instead, you create arrays that contain other arrays. Thus it's possible to create "jagged" arrays where the different sub-arrays have differing numbers of elements. In your case I'm assuming you want a 4x3 2-dimensional array, so that's what the code I wrote above creates.

Randomly select 5 elements from an array list without repeating an element

I am currently trying to make an app for iOS but I can't get some simple code down. Basically I need to randomly select 5 elements from an array list without repeating an element. I have a rough draft, but it only displays one element.
Here is my code:
let array1 = ["salmon", "turkey", "salad", "curry", "sushi", "pizza"]
let randomIndex1 = Int(arc4random_uniform(UInt32(array1.count)))
print(array1[randomIndex1])
You can do it like this:
let array1 = ["salmon", "turkey", "salad", "curry", "sushi", "pizza", "curry", "sushi", "pizza"]
var resultSet = Set<String>()
while resultSet.count < 5 {
let randomIndex = Int(arc4random_uniform(UInt32(array1.count)))
resultSet.insert(array1[randomIndex])
}
let resultArray = Array(resultSet)
print(resultArray)
A set can contain unique elements only, so it can't have the same element more than once.
I created an empty set, then as long as the array contains less than 5 elements (the number you chose), I iterated and added a random element to the set.
In the last step, we need to convert the set to an array to get the array that you want.
SWIFT 5.1
This has been answered, but I dare to come with a more simple solution.
If you take your array and convert it into a Set you will remove any duplicated items and end up with a set of unique items in no particular order since the nature of a Set is unordered.
https://developer.apple.com/documentation/swift/set
If you then convert it back to an array and pick 5 elements you will end up with an array of random items.
But it's just 1 line ;)
Example:
var original = ["A","B","C","C","C","D","E","F","G","H"]
let random = Array(Set(original)).prefix(5)
Example print:
["B", "G", "H", "E", "C"]
The only requirement is your objects must conform to the Hashable protocol. Most standard Swift types do, otherwise, it's often simple to make your own types conform.
https://developer.apple.com/documentation/swift/hashable
If you don't care about changing the original array, the following code will put the picked elements at the end of the array and then it will return the last part of the array as a slice.
This is useful if you don't care about changing the original array, the advantage is that it doesn't use extra memory, and you can call it several times on the same array.
extension Array {
mutating func takeRandomly(numberOfElements n: Int) -> ArraySlice<Element> {
assert(n <= self.count)
for i in stride(from: self.count - 1, to: self.count - n - 1, by: -1) {
let randomIndex = Int(arc4random_uniform(UInt32(i + 1)))
self.swapAt(i, randomIndex)
}
return self.suffix(n)
}
}
Example:
var array = [1,2,3,4]
let a1 = array.takeRandomly(numberOfElements: 2)
let a2 = array.takeRandomly(numberOfElements: 2)
swift-algorithms now includes an extension to Sequence called randomSample.
import Algorithm
var array1 = ["salmon", "turkey", "salad", "curry", "sushi", "pizza"]
array1.randomSample(count: 5)
Just my ยข2:
Moe Abdul-Hameed's solution has one theoretical drawback: if you roll the same randomIndex in every iteration, the while loop will never exit. It's very unlike tho.
Another approach is to create mutable copy of original array and then exclude picked items:
var source = array1
var dest = [String]()
for _ in 1...5 {
let randomIndex = Int(arc4random_uniform(UInt32(source.count)))
dest.append(source[randomIndex])
source.remove(at: randomIndex)
}
print(dest)
var array1 = ["salmon", "turkey", "salad", "curry", "sushi", "pizza"]
while array1.count > 0 {
// random key from array
let arrayKey = Int(arc4random_uniform(UInt32(array1.count)))
// your random number
let randNum = array1[arrayKey]
// make sure the number ins't repeated
array1.removeAtIndex(arrayKey)
}
By removing your picked value from array, prevent's from duplicates to be picked

Swift 3 2d array of Int

It's actually a very simple question, but after an hour I can not solve my problem.
I need to create a 2d array of Int.
var arr = [[Int]]()
or
var arr : [[Int]] = []
tried to change value :
arr[x][y] = 1
fatal error: Index out of range
Should I use APPEND or I need specify the size of the array?
I'm confused..
It's not simple really. The line:
var arr : [[Int]] = []
Creates a variable of type Array of Array of Int and initially the array is empty. You need to populate this like any other other array in Swift.
Let's step back to a single array:
var row : [Int] = []
You now have an empty array. You can't just do:
row[6] = 10
You first have to add 7 values to the array before you can access the value at index 6 (the 7th value).
With your array of arrays, you need to fill in the outer array with a whole set of inner arrays. And each of those inner arrays need to be filled out with the proper number of values.
Here is one simple way to initialize your array of arrays assuming you want a pre-filled matrix with every value set to 0.
var matrix : [[Int]] = Array(repeating: Array(repeating: 0, count: 10), count: 10)
The outer count represents the number of rows and the inner count represents the number of columns. Adjust each as needed.
Now you can access any cell in the matrix:
matrix[x][y] = 1 // where x and y are from 0 to rows-1/columns-1
Not only you need to initialize both the array and subarrays before being able to assign any values, but also each array length must be greater than the index position you are trying to set.
This is because Swift does neither initialize the subarrays for you, neither increments the array length when assigning to an index.
For instance, the following code will fail:
var a = [Int]()
a[0] = 1
// fatal error: Index out of range
Instead, you can initialize an array with the number of elements you want to hold, filling it with a default value, zero for example:
var a = Array(repeating: 0, count: 100)
a[0] = 1
// a == [1, 0, 0, 0...]
To create an matrix of 100 by 100 initialized to 0 values:
var a = Array(repeating: Array(repeating: 0, count: 100), count: 100)
a[0][0] = 1
If you don't want to specify an initial size for your matrix, you can do it this way:
var a = [[Int]]()
a.append([])
a[0].append(1)

Swift - array of strings to multiple subarrays with constant number of strings

Let's say I have this array of strings:
let Vehicles = ["Aeroplane", "Bicycle", "CarVehicle", "Lorry", "Motorbike", "Scooter", "Ship", "Train"]
What I want is this result:
let resultArray = [["Aeroplane", "Bicycle", "CarVehicle", "Lorry"], ["Motorbike", "Scooter", "Ship", "Train"]]
I know I could do this by for but I want to use Higher Order functions in Swift. I mean functions like map, reduce, filter. I think it's possible to do this way and it could be better. Can anyone help me with this? Thanks
A possible solution with map() and stride():
let vehicles = ["Aeroplane", "Bicycle", "CarVehicle", "Lorry", "Motorbike", "Scooter", "Ship", "Train"]
let each = 4
let resultArray = map(stride(from: 0, to: vehicles.count, by: each)) {
vehicles[$0 ..< advance($0, each, vehicles.count)]
}
println(resultArray)
// [[Aeroplane, Bicycle, CarVehicle, Lorry], [Motorbike, Scooter, Ship, Train]]
The usage of advance() in the closure guarantees that the code
works even if the number of array elements is not a multiple of 4
(and the last subarray in the result will then be shorter.)
You can simplify it to
let resultArray = map(stride(from: 0, to: vehicles.count, by: each)) {
vehicles[$0 ..< $0 + each]
}
if you know that the number of array elements is a multiple of 4.
Strictly speaking the elements of resultArray are not arrays
but array slices. In many cases that does not matter, otherwise you
can replace it by
let resultArray = map(stride(from: 0, to: vehicles.count, by: each)) {
Array(vehicles[$0 ..< advance($0, each, vehicles.count)])
}

swift getting an array from something like array[0..<10]

I want to get a range of objects from an array. Something like this:
var array = [1,3,9,6,3,4,7,4,9]
var newArray = array[1...3] //[3,9,6]
The above would access elements from index 1 to 3.
Also this:
newArray = array[1,5,3] // [3,4,6] would be cool
This would retrieve elements from index 1, 5 and 3 respectively.
That last example can be achieved using PermutationGenerator:
let array = [1,3,9,6,3,4,7,4,9]
let perms = PermutationGenerator(elements: array, indices: [1,5,3])
// perms is now a sequence of the values in array at indices 1, 5 and 3:
for x in perms {
// iterate over x = 3, 4 and 6
}
If you really need an array (just the sequence may be enough for your purposes) you can pass it into Array's init method that takes a sequence:
let newArray = Array(perms)
// newArray is now [3, 4, 6]
For your first example - with arrays, that will work as-is. But it looks from your comments like you're trying it with strings as well. Strings in Swift are not random-access (for reasons relating to unicode). So you can't use integers, they have an String-specific bidirectional index type:
let s = "Hello, I must be going"
if let i = find(s, "I") {
// prints "I must be going"
println(s[i..<s.endIndex])
}
This works :
var n = 4
var newArray = array[0..<n]
In any case in
Slicing Arrays in Swift you'll find a very nice sample of the Python slice using a extension to Arrays in Swift.

Resources