Those are the array models:
struct UserModel: Codable {
var userid: Int
var nickname: String
}
struct UserModelSplit: Codable {
var usr: [UserModel]
}
Initialising them:
@State private var users = [UserModel]()
@State private var userSplit = [UserModelSplit]()
Getting the first array:
for bla in userReceived{
users.append(UserModel(userid: bla.userid, nickname: bla.nickname))
}
Now I want to split it to the multidimensional array so the result should be:
userSplit[0][0] // 1th user
userSplit[0][1] // 2th user
userSplit[0][2] // 3th user
userSplit[0][3] // 4th user
userSplit[1][0] // 5th user
userSplit[1][1] // 6th user
userSplit[1][2] // 7th user
userSplit[1][3] // 8th user
I tried all kind of syntaxes and looked up how it could be done without finding anythi useful.
This is the pseudo code which sums up what I've tried:
var current = 0
var added = 0
for val in users{
userSplit[current][added] = val
added = 1
if(added == 3){
current = 1
added = 0
}
}
This pseudo code is similar to how it would actually work in PHP
I hope it's understandable :D
CodePudding user response:
You are really close, to make a 2D array you can do it like this.
struct UserModel: Codable {
var userid: Int
var nickname: String
}
var users : [UserModel] = (1...20).map({ n in
UserModel(userid: n, nickname: UUID().uuidString)
})
//Change this number to make the sub arrays the size that you want.
let size = 3
//User Split as a 2D Array
var userSplit : [[UserModel]] = stride(from: 0, to: users.count, by: size).map {
users[$0 ..< Swift.min($0 size, users.count)].map{$0}
}
for splitIdx in userSplit.indices{
print(splitIdx)
for userIdx in userSplit[splitIdx].indices {
print(userSplit[splitIdx][userIdx])
}
}
Using the other model you have it should be something like this...
struct UserModelSplit: Codable {
var usr: [UserModel]
}
//Array<UserModelSplit> NOT 2D Array
var userSplit : [UserModelSplit] = stride(from: 0, to: users.count, by: size).map {
UserModelSplit(usr: users[$0 ..< Swift.min($0 size, users.count)].map{$0})
}
for splitIdx in userSplit.indices{
print(splitIdx)
for userIdx in userSplit[splitIdx].usr.indices {
print(userSplit[splitIdx].usr[userIdx])
}
}
With both of those scenarios you will get print out that looks something like
The biggest reason your code doesn't work is because in swift you can only use
array[index] = something
to replace an existing value.
You have to
array.append(something)
when you are creating a new index.
You can split any array into a 2D array with an Array
extension
extension Array {
func split(_ size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[$0 ..< Swift.min($0 size, count)])
}
}
}
Then use
//User Split as a 2D Array
var userSplit : [[UserModel]] = users.split(size)
CodePudding user response:
You can use sequence method to iterate through your collection and initialize each subsequence into a new collection of its elements:
extension Collection {
var quadruplets: [[Element]] {
.init(
sequence(state: startIndex) { start in
guard start < endIndex else { return nil }
let end = index(start, offsetBy: 4, limitedBy: endIndex) ?? endIndex
defer { start = end }
return .init(self[start..<end])
}
)
}
}
Usage:
struct UserModel: Codable {
let userid: Int
let nickname: String
}
let users = [
(1,"a"),
(2,"b"),
(3,"c"),
(4,"d"),
(5,"e"),
(6,"f"),
(7,"g"),
(8,"h"),
(9,"i"),
(10,"j"),
].map(UserModel.init)
let userSplit = users.quadruplets
userSplit[0][0].nickname // "a"
userSplit[0][1].nickname // "b"
userSplit[0][2].nickname // "c"
userSplit[0][3].nickname // "d"
userSplit[1][0].nickname // "e"
userSplit[1][1].nickname // "f"
userSplit[1][2].nickname // "g"
userSplit[1][3].nickname // "h"
userSplit[2][0].nickname // "i"
userSplit[2][1].nickname // "j"
edit/update:
If you don't want to duplicate the collection elements you can just iterate the original collection subsequences. Something like:
extension Collection {
func unfoldSubSequences(limitedTo maxLength: Int) -> UnfoldSequence<SubSequence,Index> {
sequence(state: startIndex) { start in
guard start < endIndex else { return nil }
let end = index(start, offsetBy: maxLength, limitedBy: endIndex) ?? endIndex
defer { start = end }
return self[start..<end]
}
}
func subSequences(limitedTo maxLength: Int) -> [SubSequence] { .init(unfoldSubSequences(limitedTo: maxLength))
}
}
Usage:
let subSequences = users.subSequences(limitedTo: 4)
subSequences[0][0].nickname // "a"
subSequences[0][1].nickname // "b"
subSequences[0][2].nickname // "c"
subSequences[0][3].nickname // "d"
subSequences[1][4].nickname // "e"
subSequences[1][5].nickname // "f"
subSequences[1][6].nickname // "g"
subSequences[1][7].nickname // "h"
subSequences[2][8].nickname // "i"
subSequences[2][9].nickname // "j"
for subsequence in subSequences {
for user in subsequence {
print(user)
}
}
This will print
UserModel(userid: 1, nickname: "a")
UserModel(userid: 2, nickname: "b")
UserModel(userid: 3, nickname: "c")
UserModel(userid: 4, nickname: "d")
UserModel(userid: 5, nickname: "e")
UserModel(userid: 6, nickname: "f")
UserModel(userid: 7, nickname: "g")
UserModel(userid: 8, nickname: "h")
UserModel(userid: 9, nickname: "i")
UserModel(userid: 10, nickname: "j")
And to make it complete you can extend RangeReplaceableCollection as follow. This would work with Strings as well (Collection of Characters):
extension RangeReplaceableCollection {
func groups(limitedTo maxLength: Int) -> [Self] {
subSequences(limitedTo: maxLength).map(Self.init)
}
}
let quadruplets = "abcdefghij".groups(limitedTo: 4)
quadruplets[0] // "abcd"
quadruplets[1] // "efgh"
quadruplets[2] // "ij"