【问题标题】:How to print an array of dictionary values into a nice string in Swift如何在 Swift 中将字典值数组打印成漂亮的字符串
【发布时间】:2016-11-19 12:29:22
【问题描述】:

我有一个 routine 对象数组,它们被定义为:

struct Routine {
    let routineName: String
    let routineExercisesAndSets: [String: Int]
}

let routines: [Routine] = {
    let firstRoutine = Routine(routineName: "Legs", routineExercisesAndSets: ["Squats":4,"Lunges":4,"Calf Raises":4])

    let secondRoutine = Routine(routineName: "Chest", routineExercisesAndSets: ["Bench Press":4,"Press Ups":4,"Flyes":4,"Inclined Bench Press":4])

    let thirdRoutine = Routine(routineName: "Arms", routineExercisesAndSets: ["Bicep Curls":4,"Hammer Curls":4,"Preacher Curls":4,"Tricep Extension":4,"Tricep Dips":4])

    return [firstRoutine, secondRoutine, thirdRoutine]
}()

我试图将它们 routineExercisesAndSets 数组作为详细文本返回到 UITableViewCell 中,当使用 array.description 函数时,我在 tableView 中得到了这个结果

我的问题是,我如何遍历例程对象并打印出类似于以下内容的“漂亮”格式字符串:

"Calf Raises x 4, Squats x 4, Lunges x 4..."

我可以使用以下代码在新行上打印出单独的键、值对:

for i in routines{
    for (key, value) in (i.routineExercisesAndSets)! {
        print("\(key) x \(String(value))")
    }
}

产生:

Calf Raises x 4 Squats x 4 Lunges x 4 Bench Press x 4 Press Ups x 4 Flyes x 4 Inclined Bench Press x 4 Tricep Extension x 4 Tricep Dips x 4 Preacher Curls x 4 Hammer Curls x 4 Bicep Curls x 4

但我想按它们的父对象对它们进行分组,以便例程的练习显示在同一行,因此它看起来像示例 "Calf Raises x 4, Squats x 4, Lunges x 4..."

【问题讨论】:

    标签: ios arrays swift dictionary


    【解决方案1】:

    您可以使用链接的mapjoined 操作来构造单个String,描述给定练习的练习字典。例如

    for routine in routines {
        print("Routine:", routine.routineName)
        print("--------------")
        print(routine.routineExercisesAndSets
            .map { $0 + " x \($1)" }
            .joined(separator: ", "))
        print()
    }
    /* Routine: Legs
       --------------
       Calf Raises x 4, Squats x 4, Lunges x 4
    
       Routine: Chest
       --------------
       Bench Press x 4, Press Ups x 4, Flyes x 4, Inclined Bench Press x 4
    
       Routine: Arms
       --------------
       Tricep Extension x 4, Tricep Dips x 4, Preacher Curls x 4, Hammer Curls x 4, Bicep Curls x 4 
    
                       */
    

    此外,您可以将它们实现为Routine 的计算description 属性的返回,而不是在每次使用时显式执行这些“表示”转换,作为让Routine 符合CustomStringConvertible 的一部分:

    extension Routine: CustomStringConvertible {
        var description: String {
            return routineName + ":\n" + routineExercisesAndSets
                .map { $0 + " x \($1)" }
                .joined(separator: ", ")
        }
    }
    
    for routine in routines {
        print(routine) /* uses Routine:s implementation of 'CustomStringConvertible',
                          the computed property 'description`, specifically           */
        print()
    }
    /* Legs:
       Calf Raises x 4, Squats x 4, Lunges x 4
    
       Chest:
       Bench Press x 4, Press Ups x 4, Flyes x 4, Inclined Bench Press x 4
    
       Arms:
       Tricep Extension x 4, Tricep Dips x 4, Preacher Curls x 4, Hammer Curls x 4, Bicep Curls x 4
    
                       */
    

    鉴于您在下面的评论,Routine 的属性 routineNameroutineExercisesAndSets 似乎是可选的。如果是这种情况,您自然需要在访问它们的(可能存在的)值之前处理它们的展开。例如,如果两个属性中的任何一个是 nil,则返回一个空的 description,否则返回组合的例程名称和详细信息描述(如上面的非可选示例中所做的那样):

    struct Routine {
        let routineName: String?
        let routineExercisesAndSets: [String: Int]?
    }
    
    extension Routine: CustomStringConvertible {
        var description: String {
            guard let name = routineName, let details = routineExercisesAndSets else { return "" }
            return name + ":\n" + details.map { $0 + " x \($1)" }.joined(separator: ", ")
        }
    }
    

    【讨论】:

    • 我总是使用命名参数
    • 尝试使用for routine in routines { print("Routine:", routine.routineName) print("--------------") print(routine.routineExercisesAndSets .map { $0.0 + " x \($0.1)" } .joined(separator: ", ")) print() } 时出现错误“[String: Int] 类型的值没有成员 0
    • 这是我正在使用的确切代码,我已经在另一个文件中声明了 Struct。 This is my code
    • @MHDev 这与上面的示例不同:您没有告诉我们您的属性是可选的。在访问它们(可能存在的)值之前,您自然需要处理这些解包。例如。使用 nil 合并运算符:print(routine.routineExercisesAndSets? .map { $0.0 + " x \($0.1)" } .joined(separator: ", ") ?? "routineExercisesAndSets is nil")
    • 优秀的答案。 (已投票)
    【解决方案2】:

    首先让我们将RoutineCustomStringConvertible 一致

    extension Routine: CustomStringConvertible {
        var description: String {
            return routineExercisesAndSets.map { $0 + " x " + $1.description }.joined(separator: ", ")
        }
    }
    

    现在你可以轻松写了

    routines.forEach { print($0) }
    

    结果

    Calf Raises x 4, Squats x 4, Lunges x 4
    Bench Press x 4, Press Ups x 4, Flyes x 4, Inclined Bench Press x 4
    Tricep Extension x 4, Tricep Dips x 4, Preacher Curls x 4, Hammer Curls x 4, Bicep Curls x 4
    

    或者给定一个UITableViewCell...

    let cell: UITableViewCell = ...
    let routine: Routine = ...
    cell.detailTextLabel?.text = routine.description
    

    【讨论】:

    • 请注意,description 不会覆盖此实现中的例程名称(我在符合CustomStringCovertible 的示例中还包括例程名称,通过链接.map.joined 应用于@ 987654332@ :) )。但也许 OP 只想要描述中的练习。
    • @dfri:正确,routinename 不包含在此示例的描述中。
    • ... 省略号:我在编辑添加 UITableViewCell 示例之前(确切时间)写了我的评论。加上这一点,当将description 应用到detailTextLabel 时,最好不要包含例程名称 (Y)
    猜你喜欢
    • 2020-11-10
    • 2017-02-22
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 2013-07-07
    • 1970-01-01
    • 1970-01-01
    • 2020-11-19
    相关资源
    最近更新 更多