如何完全遍历数组?

时间:2016-12-25 11:29:42

标签: arrays swift

我有以下代码,我正在尝试打印booksAssigned和booksAssignedDue,具体取决于ChaptersToRead

var books:[String] = ["Hobbit","LOTR","Fellowship"]
var chaptersToRead:[[Int]] = [[1],[1,2],[2]]

var booksAssigned:[String] = []
var booksAssignedDue:[String] = []

for (index, chapters) in chaptersToRead.enumerated() {
    if chapters.contains(1) {
        booksAssigned.append(books[index])
    }
    else
    {
        booksAssignedDue.append(books[index])
    }
}

我的预期输出是

print(booksAssigned) = ["Hobbit","LOTR"]
print(booksAssignedDue) = ["LOTR","Fellowship"]

但我得到了这个

print(booksAssigned) = ["Hobbit","LOTR"]
print(booksAssignedDue) = ["Fellowship"]

我做错了什么?

2 个答案:

答案 0 :(得分:4)

试试这个:

for (index, chapters) in chaptersToRead.enumerated() {
    if chapters.contains(1) {
        booksAssigned.append(books[index])
    }
    //You should not use `else` here.
    if chapters.contains(2) {
        booksAssignedDue.append(books[index])
    }
}

如果您在标记的位置使用else,则添加到booksAssigned的图书无法添加到booksAssignedDue

答案 1 :(得分:1)

两个序列之间的成对关系:考虑使用zip(_:_:)

当你处理具有成对元素关系的序列(/有序集合)时(例如books中的书和chaptersToRead中的相关章节列表),它是合适且有用的使用全局zip(_:_:)函数来处理压缩序列:

// no need to explicitly annotate type: it will be correctly inferred
let books =          ["Hobbit", "LOTR", "Fellowship"]
let chaptersToRead = [[1],      [1,2],  [2]]

// apply a flatMap over the zipped collection of the books and the
// associated chapters to read, with a 'nil' conditional for the '1'
// and '2' inclusions for booksAssigned and booksAssignedDue, respectively.
let booksAssigned = zip(books, chaptersToRead)
    .flatMap { $1.contains(1) ? $0 : nil }
let booksAssignedDue = zip(books, chaptersToRead)
    .flatMap { $1.contains(2) ? $0 : nil }

print(booksAssigned)    // ["Hobbit", "LOTR"]
print(booksAssignedDue) // ["LOTR", "Fellowship"]

使用这种方法,您不需要预先声明并重复附加到可变数组,但可以使用压缩序列上的booksAssigned操作直接实例化flatMap数组。您还可以避免使用从外部“源”接收的索引显式访问数组的索引(在这种情况下,是另一个的索引,尽管是相关的数组),这种方法可能导致危险,因为索引是使用前未使用过。

另请注意,我已将上面的所有数组更改为不可变项:除非您确定要改变属性/变量,否则最好使用不可变项(可能您希望在应用此实现的实际上下文中使用不可变项) )。

利用适当的数据结构

使用密切相关的序列时的另一个见解是,您可能需要考虑简单地以适当的类型连接这些成对的元素(例如,它涵盖了与书籍相关的boks标题和章节),这将允许简单地使用具有此类元素的单个数组,而不是几个单独的数组。

struct Book {
    let title: String
    let chaptersToRead: [Int]
}
/* possibly `chaptersToRead` should be a mutable property rather 
   than an immutable one, in case you plan to mutate it for an 
   existing `Book` instance.                                      */

let books = [Book(title: "Hobbit",     chaptersToRead: [1]),
             Book(title: "LOTR",       chaptersToRead: [1, 2]),
             Book(title: "Fellowship", chaptersToRead: [2])]

let booksAssigned = books
    .flatMap { $0.chaptersToRead.contains(1) ? $0.title : nil }
let booksAssignedDue = books
    .flatMap { $0.chaptersToRead.contains(2) ? $0.title : nil }

print(booksAssigned)    // ["Hobbit", "LOTR"]
print(booksAssignedDue) // ["LOTR", "Fellowship"]

或者,使用此方法,您可能希望使用已过滤的Book个实例而不仅仅是title个属性:

let booksAssigned = books.filter { $0.chaptersToRead.contains(1) }
let booksAssignedDue = books.filter { $0.chaptersToRead.contains(2) }

如果您将与给定Book个实例数组关联的标题设置为String个实例数组,则可以在.map { $0.title }上应用[Book]轻松获取这些标题。数组。