【问题标题】:Swift - Convert array to multidimensional arraySwift - 将数组转换为多维数组
【发布时间】:2022-11-27 10:27:16
【问题描述】:

这些是数组模型:

struct UserModel: Codable {
    var userid: Int
    var nickname: String
}

struct UserModelSplit: Codable {
    var usr: [UserModel]
}

初始化它们:

@State private var users = [UserModel]()
@State private var userSplit = [UserModelSplit]()

获取第一个数组:

for bla in userReceived{
    users.append(UserModel(userid: bla.userid, nickname: bla.nickname))
}

现在我想把它拆分成多维数组,所以结果应该是:

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

我尝试了所有类型的语法并查找了它是如何完成的,但没有找到任何有用的东西。

这是总结我尝试过的伪代码:

var current = 0
var added = 0
for val in users{
    userSplit[current][added] = val
    
    added += 1
    if(added == 3){
        current += 1
        added = 0
    }
}

此伪代码类似于它在 PHP 中的实际工作方式

我希望这是可以理解的:D

【问题讨论】:

  • 当您写 userSplit[0][0] // 1th user 时,您实际上是指 userSplit[0].usr[0] 吗?
  • 无论 users 数组中有多少元素,目标是将每个 UserModelSplit 的 4 个元素分组吗?如果有 6 或 7 个用户怎么办?如果有 9 或 10 等怎么办?请更好地解释您想要的逻辑。
  • 你是说你想要一个[[UserModel]],其中内部数组是来自主序列的 3 个用户的块? (如果您使用示例输出而不是伪代码,则为 4 个块!)
  • 是的 :D 现在我添加了这个细节:userSplit[current].usr[added] = val 我在这一行收到错误:“线程 1:致命错误:索引超出范围”,如何解决这个问题?
  • 如果有 6 个用户,那么: userSplit[0][0] // 第一个用户 userSplit[0][1] // 第二个用户 userSplit[0][2] // 第三个用户 userSplit[0][3] //第 4 个用户 userSplit[1][0] // 第 5 个用户 userSplit[1][1] // 第 6 个用户并在此处停止

标签: swift


【解决方案1】:

你真的很接近,要制作一个二维数组,你可以这样做。

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])
    }
}
 

使用你拥有的其他模型应该是这样的......

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])
    }
}

在这两种情况下,您将打印出看起来像

您的代码不起作用的最大原因是因为在 swift 中您只能使用

array[index] = something 

替换现有值。

你必须

array.append(something)

当您创建新索引时。

您可以使用 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)])
        }
    }
}

然后使用

//User Split as a 2D Array
var userSplit : [[UserModel]] = users.split(size)

【讨论】:

  • Jesus :D 这将需要一段时间,因为模型已针对问题进行了简化,我会在它起作用时立即接受,或者在它不起作用时提出进一步的问题
  • @user19559647 此代码在 playground 中有效,只需确保您知道二维数组和包含另一个数组的对象数组之间的区别
  • .map{$0} 的目的是将 ArraySlice 转换为数组吗?这似乎不如 Array(users[$0 ..&lt; Swift.min($0 + size, users.count)]) 明显。
  • @HangarRash 是的,我想说明没有切片的类型,但你的方法也有效
  • 好的,第一个解决方案有效,我相信第二个解决方案也可以,谢谢! :)
【解决方案2】:

您可以使用 sequence 方法遍历您的集合并将每个子序列初始化为其元素的新集合:

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])
            }
        )
    }
}

用法:

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"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-26
    • 2019-06-29
    • 1970-01-01
    • 1970-01-01
    • 2015-11-17
    相关资源
    最近更新 更多