【问题标题】:Check if optional array is empty检查可选数组是否为空
【发布时间】:2015-02-19 17:48:44
【问题描述】:

在 Objective-C 中,当我有一个数组时

NSArray *array;

我想检查它是否不为空,我总是这样做:

if (array.count > 0) {
    NSLog(@"There are objects!");
} else {
    NSLog(@"There are no objects...");
}

这样,就不需要检查是否array == nil,因为这种情况会导致代码陷入else的情况,以及非nil但空数组可以。

但是,在 Swift 中,我偶然发现了我有一个可选数组的情况:

var array: [Int]?

我无法弄清楚要使用哪个条件。我有一些选择,例如:

选项 A: 在相同条件下检查非nil 和空案例:

if array != nil && array!.count > 0 {
    println("There are objects")
} else {
    println("No objects")
}

选项 B: 使用 let 取消绑定数组:

if let unbindArray = array {
    if (unbindArray.count > 0) {
        println("There are objects!")
    } else {
        println("There are no objects...")
    }
} else {
    println("There are no objects...")
}

选项 C: 使用 Swift 提供的合并运算符:

if (array?.count ?? 0) > 0 {
    println("There are objects")
} else {
    println("No objects")
}

我不太喜欢 B 选项,因为我在两种情况下重复代码。但我不确定选项 AC 是否正确,或者我应该使用任何其他方式。

我知道根据情况可以避免使用可选数组,但在某些情况下可能需要询问它是否为空。所以我想知道最简单的方法是什么。


编辑:

正如@vacawama 所指出的,这种简单的检查方法是有效的:

if array?.count > 0 {
    println("There are objects")
} else {
    println("No objects")
}

但是,我正在尝试仅当它是 nil 或为空时才想做一些特殊的事情,然后不管数组是否有元素都继续。所以我尝试了:

if array?.count == 0 {
    println("There are no objects")
}

// Do something regardless whether the array has elements or not.

还有

if array?.isEmpty == true {
    println("There are no objects")
}

// Do something regardless whether the array has elements or not.

但是,当数组为nil 时,它不会落入if 体内。这是因为,在这种情况下,array?.count == nilarray?.isEmpty == nil,所以表达式 array?.count == 0array?.isEmpty == true 都计算为 false

所以我想弄清楚是否有任何方法可以仅在一个条件下实现这一目标。

【问题讨论】:

  • 您是否有理由将数组设为可选?对于表格视图和我使用非可选的东西,因为(就像你说的)nil 与没有对象相同,因此通过删除 nil 可以降低复杂性而不会丢失任何功能。
  • 我认为选项A 是最易读的。这是你唯一应该关心的事情。

标签: ios arrays swift


【解决方案1】:

Swift 扩展:

extension Optional where Wrapped: Collection {
    var nilIfEmpty: Optional {
        switch self {
        case .some(let collection):
            return collection.isEmpty ? nil : collection
        default:
            return nil
        }
    }

    var isNilOrEmpty: Bool {
        switch self {
        case .some(let collection):
            return collection.isEmpty
        case .none:
            return true
    }
}

用法:

guard let array = myObject?.array.nilIfEmpty else { return }

或:

if myObject.array.isNilOrEmpty {
    // Do stuff here
}

【讨论】:

    【解决方案2】:

    最好使用 if 来检查空数组。为什么是 bcoz,例如,如果我们试图在列表数组中找到最大的整数,显然我们会将 list[0] 与列表中的每个整数进行比较。那时它给了我们 Index out of range 异常......你可以用 IF & Guard 试试这个

    func findGreatestInList(list: [Int]?)-> Int? {
            if list!.count == 0 {
                print("List is empty")
                return nil
               
           }
           /*guard list!.isEmpty else {
                print("List is empty")
                return nil
            }*/
            var greatestValue = list![0]
                for number in 0...list!.count-1 {
                
                  if list![number] > greatestValue {
                    greatestValue = list![number]
    

    【讨论】:

      【解决方案3】:

      Swift 3 及更高版本的更新答案:

      Swift 3 移除了将选项与 >< 进行比较的功能,因此之前答案的某些部分不再有效。

      仍然可以将可选项与== 进行比较,因此检查可选项数组是否包含值的最直接方法是:

      if array?.isEmpty == false {
          print("There are objects!")
      }
      

      其他方法:

      if array?.count ?? 0 > 0 {
          print("There are objects!")
      }
      
      if !(array?.isEmpty ?? true) {
          print("There are objects!")
      }
      
      if array != nil && !array!.isEmpty {
          print("There are objects!")
      }
      
      if array != nil && array!.count > 0 {
          print("There are objects!")
      }
      
      if !(array ?? []).isEmpty {
          print("There are objects!")
      }
      
      if (array ?? []).count > 0 {
          print("There are objects!")
      }
      
      if let array = array, array.count > 0 {
          print("There are objects!")
      }
      
      if let array = array, !array.isEmpty {
          print("There are objects!")
      }
      

      如果你想在数组为nil或者为空的时候做点什么,你至少有6个选择:

      选项 A:

      if !(array?.isEmpty == false) {
          print("There are no objects")
      }
      

      选项 B:

      if array == nil || array!.count == 0 {
          print("There are no objects")
      }
      

      选项 C:

      if array == nil || array!.isEmpty {
          print("There are no objects")
      }
      

      选项 D:

      if (array ?? []).isEmpty {
          print("There are no objects")
      }
      

      选项 E:

      if array?.isEmpty ?? true {
          print("There are no objects")
      }
      

      选项 F:

      if (array?.count ?? 0) == 0 {
          print("There are no objects")
      }
      

      选项 C 准确地捕捉到了你用英文描述的方式:“我想做一些特别的事情,只有当它为 nil 或为空时。”我建议你使用这是因为它很容易理解。这没有什么问题,特别是因为如果变量是nil,它会“短路”并跳过对空的检查。



      Swift 2.x 的上一个答案:

      你可以这样做:

      if array?.count > 0 {
          print("There are objects")
      } else {
          print("No objects")
      }
      

      正如@Martin 在 cmets 中指出的那样,它使用func ><T : _Comparable>(lhs: T?, rhs: T?) -> Bool,这意味着编译器将0 包装为Int?,以便可以与左侧的Int? 进行比较,因为的可选链调用。

      以类似的方式,您可以这样做:

      if array?.isEmpty == false {
          print("There are objects")
      } else {
          print("No objects")
      }
      

      注意:您必须在此处明确地与false 进行比较才能使其正常工作。


      如果你想在数组为nil或者为空的时候做点什么,你至少有7个选择:

      选项 A:

      if !(array?.count > 0) {
          print("There are no objects")
      }
      

      选项 B:

      if !(array?.isEmpty == false) {
          print("There are no objects")
      }
      

      选项 C:

      if array == nil || array!.count == 0 {
          print("There are no objects")
      }
      

      选项 D:

      if array == nil || array!.isEmpty {
          print("There are no objects")
      }
      

      选项 E:

      if (array ?? []).isEmpty {
          print("There are no objects")
      }
      

      选项 F:

      if array?.isEmpty ?? true {
          print("There are no objects")
      }
      

      选项 G:

      if (array?.count ?? 0) == 0 {
          print("There are no objects")
      }
      

      选项 D 准确地捕捉到了你用英文描述的方式:“我想做一些特别的事情,只有当它为 nil 或为空时。”我建议你使用这是因为它很容易理解。这没有什么问题,特别是如果变量是nil,它会“短路”并跳过空检查。

      【讨论】:

      • 这行得通。仅出于完整性考虑:它使用func ><T : _Comparable>(lhs: T?, rhs: T?) -> Bool 运算符,右侧的0 被编译器包装成Int?
      • 我刚刚注意到var opt : Int? = nilopt < 0 的计算结果为true。此处不相关但可能出乎意料,并且可能是一个参数反对比较可选整数。
      • nil 小于任何非零值 Int 你扔给它,甚至是负值。它必须在包装类型的一端或另一端,因为< 的任何实现都必须是一个总顺序,并且 optional 可以包装任何可比较的类型。我认为 nil 小于任何东西是直观的,因为如果有人对可能为空白的一列数字进行排序,我认为他们会期望空白出现在 1 之前。或者,一个 nil 数组变量甚至比一个空的更空数组:)
      • 谢谢,@vacawama。您指出的选项有效。但是,我走得更远,尝试了另一种特殊情况:只测试数组是 nil 还是空,不管它有元素时做什么。我将编辑我的问题,以便您查看。
      • @Rambatino,如果arraynil!(array?.isEmpty == false) 将是true,但如果array 是@9876543676@,array?.isEmpty == true 将是false,因为@9876543676@ 是@4不等于true。我们希望将 nil array 视为空。
      【解决方案4】:

      与其使用ifelse,不如使用guard 来检查空数组而不为同一数组创建新变量。

      guard !array.isEmpty else {
          return
      }
      // do something with non empty ‘array’
      

      【讨论】:

      • 用代码解释会提高答案的质量。
      • 一个好的答案有一个更好的解释How do I write a good answer?
      • 如果数组是可选的,这不起作用,如问题中所述。
      【解决方案5】:

      优雅的内置解决方案是 Optional 的 map 方法。这种方法经常被遗忘,但它正是你所需要的;它允许您安全地向包裹在 Optional 中的事物发送消息。在这种情况下,我们以一种三路开关结束:我们可以对 Optional 数组说 isEmpty,并得到 true、false 或 nil(如果数组本身为 nil)。

      var array : [Int]?
      array.map {$0.isEmpty} // nil (because `array` is nil)
      array = []
      array.map {$0.isEmpty} // true (wrapped in an Optional)
      array?.append(1)
      array.map {$0.isEmpty} // false (wrapped in an Optional)
      

      【讨论】:

        【解决方案6】:

        Collection 协议的扩展属性

        *用 Swift 3 编写

        extension Optional where Wrapped: Collection {
            var isNilOrEmpty: Bool {
                switch self {
                    case .some(let collection):
                        return collection.isEmpty
                    case .none:
                        return true
                }
            }
        }
        

        使用示例:

        if array.isNilOrEmpty {
            print("The array is nil or empty")
        }
        

         

        其他选项

        除了上面的扩展之外,我发现以下选项最清晰,无需强制展开选项。我将其解读为展开可选数组,如果为 nil,则替换为相同类型的空数组。然后,获取(非可选)结果,如果它isEmpty 执行条件代码。

        推荐

        if (array ?? []).isEmpty {
            print("The array is nil or empty")
        }
        

        虽然以下内容读得很清楚,但我建议养成尽可能避免强制解包选项的习惯。尽管在这种特定情况下执行array!.isEmpty 时,您可以保证array 永远不会是nil,但以后很容易对其进行编辑并无意中引入崩溃。当您习惯于强制展开可选选项时,您会增加有人在未来做出可编译但在运行时崩溃的更改的机会。

        不推荐!

        if array == nil || array!.isEmpty {
            print("The array is nil or empty")
        }
        

        我发现包含 array?(可选链接)的选项令人困惑,例如:

        令人困惑?

        if !(array?.isEmpty == false) {
            print("The array is nil or empty")
        }
        
        if array?.isEmpty ?? true {
            print("There are no objects")
        }
        

        【讨论】:

          【解决方案7】:

          有条件的展开:

          if let anArray = array {
              if !anArray.isEmpty {
                  //do something
              }
          }
          

          编辑:自 Swift 1.2 起可能:

          if let myArray = array where !myArray.isEmpty {
              // do something with non empty 'myArray'
          }
          

          编辑:自 Swift 2.0 起可能:

          guard let myArray = array where !myArray.isEmpty else {
              return
          }
          // do something with non empty 'myArray'
          

          【讨论】:

          • 他还是要检查是否是空的。这只是检查可选是否不包含数组。
          • 是的,那么你可以这样做if array? != nil && !(array!.isEmpty) {}
          • 你可以简单地展开它,因为如果数组为 nil 并且无法展开,则不会执行该行
          • 你不认为必须在同一行写array?array! 是代码异味吗?这就是条件展开的用途。
          • 但请注意,您必须使用逻辑 & 运算符 -> 您必须使用 && 而不是 &。否则当数组为 nil 时可能会出错
          【解决方案8】:

          选项 D: 如果数组不需要是可选的,因为您只关心它是否为空,请将其初始化为空数组而不是可选的:

          var array = [Int]()
          

          现在它将永远存在,您只需检查isEmpty

          【讨论】:

          • 虽然我同意这一点,但问题是我们不知道 OP 到底想要什么。根据所使用的 API,数组可能有内容,也可能为 nil。 Or 为 nil、空或包含值。而且每种情况都有不同的解决方案。
          • 同意,我只是提出一个我个人认为有用的选项。
          • 大声笑,是的。在阅读您的答案之前,我刚刚评论了这个确切的事情。伟大的思想... :-)
          • 表格视图正是我想到的情况!
          猜你喜欢
          • 1970-01-01
          • 2017-09-13
          • 2011-11-04
          • 2022-01-25
          • 2011-07-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-23
          相关资源
          最近更新 更多