【问题标题】:For Loops and Switches in SwiftSwift 中的 For 循环和开关
【发布时间】:2020-07-27 21:54:32
【问题描述】:

我(相对)是编程新手。我正在阅读 Apple 的“应用程序开发简介”,由于没有某种答案手册,我不得不自己解决问题。但是有些事情我有点困惑:

我正在处理一个问题:

这个游乐场内置了鸡类型。鸡有品种和脾气属性,这两个属性都是枚举。

这是一组鸡: 鸡 = [{silkie, 脾气暴躁}...]

任务是计算数组中有多少只品种“leghorn”和脾气“hilarious”的鸡。我想出了以下代码:

var chickenOfInterestCount = 0

for chicken in chickens {
    switch chicken.temper {
    case .hilarious:
        switch chicken.breed {
        case .leghorn:
            chickenOfInterestCount += 1
        default:
            chickenOfInterestCount += 0
        }
    default:
        chickenOfInterestCount += 0
    }
}


chickenOfInterestCount

它有效,但我想知道是否有更有效的方法来做到这一点?我可以让开关检查每只鸡的 {leghorn, hilarious} 并直接计算所需鸡的数量,而不是使用嵌套开关吗? (我自己尝试的所有尝试都被看起来很吓人的错误消息压制了,所以我猜不是)从那以后,for循环如何工作?

当我最初学习 for 循环时,我的印象是整数是用来循环的,例如第一个循环是 i = 0,执行里面的代码,然后第二个循环是 i = 1,依此类推,其中“i”实际上可以是任何东西,想法是一样的。这里用的是“鸡”。为什么我可以将条件设​​置为 chicken.temper?鸡在这里是什么意思? for 循环是否尊重它循环通过的数组的类型?那么这里实际发生的情况是否类似于“在鸡阵列中取第 0 只鸡,称其为‘鸡’,然后检查它的脾气”?

【问题讨论】:

    标签: swift for-loop switch-statement


    【解决方案1】:

    欢迎来到编程。这是您场景的模型。

      struct Chicken{
            let id:Int
            let breed:String
            let temper:String
        }
        
        enum Breed{
            static let leghorn = "leghorn"
            static let other = "other"
        }
        
        enum Temper{
            static let hilarious = "hilarious"
            static let other = "other"
        }
        
        
        var chickens:[Chicken] = []
        chickens.append(Chicken(id: 1, breed:.leghorn, temper:.hilarious))
        chickens.append(Chicken(id: 2, breed:.other, temper:.hilarious))
        chickens.append(Chicken(id: 3, breed:.leghorn, temper:.other))
    

    你可以用Swift从一行得到你的结果。使用过滤函数。这就像for循环,$0表示当前元素。它循环遍历你的数组并找到满足你条件的元素。

    print(chickens.filter({$0.breed == .leghorn && $0.temper == .hilarious}).count)
    

    Apple Documentation

    Extra info

    【讨论】:

    • Swift 是一种类型推断语言{$0.breed == .leghorn && $0.temper == .hilarious} 它也适用于您的附加方法.init(id: 1, breed: .leghorn, temper: .hilarious)。顺便说一句,您为什么在枚举中使用静态属性而不是常规情况? enum Temper: String { case hilarious, other }
    • 如果是为了避免使用rawValue属性,最好使用结构
    • @LeoDabus 感谢先生您的指示。我只是用静态类型来解释过滤方法。
    • 看看我对 Ben 的回答的评论。它也适用于这里
    【解决方案2】:

    嗯,我要提到的第一件事是您的方法有效。正如您所怀疑的那样,这不是最优雅的方法 - 但您已经本能地意识到了这一点。

    Swift 中的过滤器功能强大而高效,Dilan 的示例将为您提供正确的方向来开始探索这一点。但是,除了 map、reduce 和 filter 等函数式编程特性之外,您还需要对控制流本身有一个很好的理解。

    对于这种情况,如果您只寻找品种和气质的一种组合,那么基本的 if 语句可能比使用 switch 更简洁。

    var chickenOfInterestCount = 0
    
    for chicken in chickens {
        if chicken.breed == .leghorn && chicken.temper == .hilarious {
            chickenOfInterestCount += 1
        }
    }
    
    chickenOfInterestCount
    

    当你必须为每种情况做一些事情时,Switch 会更有用 - 它最终比多个 if / else if 语句更干净。

    var bantamCount = 0
    var leghornCount = 0
    var unknownBreedCount = 0
    
    var chillCount = 0
    var hilariousCount = 0
    var unknownTemperCount = 0
    
    for chicken in chickens {
    
        switch chicken.breed {
        case .bantam:
            bantamCount += 1
        case .leghorn:
            leghornCount += 1
        default:
            unknownBreedCount += 1
        }
    
        switch chicken.temper {
        case .chill:
            chillCount += 1
        case .hilarious:
            hilariousCount += 1
        default:
            unknownTemperCount += 1
        }
    
    }
    

    关于你的问题:

    那么这里实际发生的事情是不是像“在鸡阵列中取第 0 只鸡,称它为‘鸡’,然后检查它的脾气”?

    正如 Ben 指出的那样,您对此的推理是正确的。在循环范围内,有一个名为 chicken 的 var,它是 Chicken 的一个实例(大概 - 不确定您将这个 Class 或 Struct 命名为什么)并且是 chickens 数组的成员。

    【讨论】:

      【解决方案3】:

      在这些情况下,Swift-y 要做的事情是打破 map()reduce()compactMap()、和 filter()——在你的情况下,filter():

      let chickens: [Chicken] = [ silkie, grumpy, dopey, foghorn ]
      
      let hilariousLeghorns = chickens.filter { 
          $0.breed == .leghorn 
              && $0.temper == .hilarious 
      }
      
      let chickenOfInterestCount = hilariousLeghorns.count
      

      (感谢您让您的示例变得有趣!)

      在您的伪代码中,您的 for 循环有点嵌套,难以阅读。 (我的可能并不容易——我喜欢代码审查!)事实上,您声明了一个 chicken ,它将被分配 chickens 的每个元素的值em> 依次。您可以使用任何序列来执行此操作,例如数组、映射或集合。

      要获得老式的 for 循环,您可以遍历一个范围:

      for i in 1...5 { 
          print(i)
      }
      

      这做同样的事情:i 被赋值为 1、2、3、4 和 5,依次循环 5 次。

      【讨论】:

      • 另一种选择是使用reduce而不是过滤元素,然后访问结果计数chickens.reduce(0) { $1.breed == .leghorn && $1.temper == .hilarious ? $0+1 : $0 }
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-06
      • 2014-09-01
      • 1970-01-01
      • 2014-07-26
      • 2023-03-22
      • 2023-03-30
      • 2019-01-06
      相关资源
      最近更新 更多