Có một hàm mà tôi có thể sử dụng để lặp qua một mảng và có cả chỉ mục và phần tử, như liệt kê của Python không?
for index, element in enumerate(list):
...
Có một hàm mà tôi có thể sử dụng để lặp qua một mảng và có cả chỉ mục và phần tử, như liệt kê của Python không?
for index, element in enumerate(list):
...
Câu trả lời:
Đúng. Kể từ Swift 3.0, nếu bạn cần chỉ mục cho từng thành phần cùng với giá trị của nó, bạn có thể sử dụng enumerated()
phương thức để lặp qua mảng. Nó trả về một chuỗi các cặp bao gồm chỉ mục và giá trị cho từng mục trong mảng. Ví dụ:
for (index, element) in list.enumerated() {
print("Item \(index): \(element)")
}
Trước Swift 3.0 và sau Swift 2.0, chức năng được gọi là enumerate()
:
for (index, element) in list.enumerate() {
print("Item \(index): \(element)")
}
Trước Swift 2.0, enumerate
là một chức năng toàn cầu.
for (index, element) in enumerate(list) {
println("Item \(index): \(element)")
}
enumerate
?
enumerating
cho Swift 4. Thật thú vị!
for (index, element) in
khi sử dụng enumerated
là sai lệch. nên làfor (offset, element) in
Swift 5 cung cấp một phương thức được gọi là enumerated()
cho Array
. enumerated()
có tuyên bố sau:
func enumerated() -> EnumeratedSequence<Array<Element>>
Trả về một chuỗi các cặp (n, x), trong đó n đại diện cho một số nguyên liên tiếp bắt đầu từ 0 và x đại diện cho một phần tử của chuỗi.
Trong trường hợp đơn giản nhất, bạn có thể sử dụng enumerated()
với vòng lặp for. Ví dụ:
let list = ["Car", "Bike", "Plane", "Boat"]
for (index, element) in list.enumerated() {
print(index, ":", element)
}
/*
prints:
0 : Car
1 : Bike
2 : Plane
3 : Boat
*/
Tuy nhiên, xin lưu ý rằng bạn không bị giới hạn sử dụng enumerated()
với vòng lặp for. Trong thực tế, nếu bạn dự định sử dụng enumerated()
với một vòng lặp for cho một cái gì đó tương tự như đoạn mã sau, thì bạn đã làm sai:
let list = [Int](1...5)
var arrayOfTuples = [(Int, Int)]()
for (index, element) in list.enumerated() {
arrayOfTuples += [(index, element)]
}
print(arrayOfTuples) // prints [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]
Một cách nhanh hơn để làm điều này là:
let list = [Int](1...5)
let arrayOfTuples = Array(list.enumerated())
print(arrayOfTuples) // prints [(offset: 0, element: 1), (offset: 1, element: 2), (offset: 2, element: 3), (offset: 3, element: 4), (offset: 4, element: 5)]
Để thay thế, bạn cũng có thể sử dụng enumerated()
với map
:
let list = [Int](1...5)
let arrayOfDictionaries = list.enumerated().map { (a, b) in return [a : b] }
print(arrayOfDictionaries) // prints [[0: 1], [1: 2], [2: 3], [3: 4], [4: 5]]
Hơn nữa, mặc dù nó có một số hạn chế , forEach
có thể là sự thay thế tốt cho vòng lặp for:
let list = [Int](1...5)
list.reversed().enumerated().forEach { print($0, ":", $1) }
/*
prints:
0 : 5
1 : 4
2 : 3
3 : 2
4 : 1
*/
Bằng cách sử dụng enumerated()
và makeIterator()
, bạn thậm chí có thể lặp lại thủ công trên của bạn Array
. Ví dụ:
import UIKit
import PlaygroundSupport
class ViewController: UIViewController {
var generator = ["Car", "Bike", "Plane", "Boat"].enumerated().makeIterator()
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(type: .system)
button.setTitle("Tap", for: .normal)
button.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
button.addTarget(self, action: #selector(iterate(_:)), for: .touchUpInside)
view.addSubview(button)
}
@objc func iterate(_ sender: UIButton) {
let tuple = generator.next()
print(String(describing: tuple))
}
}
PlaygroundPage.current.liveView = ViewController()
/*
Optional((offset: 0, element: "Car"))
Optional((offset: 1, element: "Bike"))
Optional((offset: 2, element: "Plane"))
Optional((offset: 3, element: "Boat"))
nil
nil
nil
*/
enumerate
?
Tôi đã tìm thấy câu trả lời này trong khi tìm kiếm một cách để làm điều đó với Từ điển , và hóa ra nó khá dễ dàng để điều chỉnh nó, chỉ cần vượt qua một tuple cho phần tử.
// Swift 2
var list = ["a": 1, "b": 2]
for (index, (letter, value)) in list.enumerate() {
print("Item \(index): \(letter) \(value)")
}
Bạn chỉ có thể sử dụng vòng lặp liệt kê để có kết quả mong muốn:
Swift 2:
for (index, element) in elements.enumerate() {
print("\(index): \(element)")
}
Swift 3 & 4:
for (index, element) in elements.enumerated() {
print("\(index): \(element)")
}
Hoặc bạn có thể chỉ cần đi qua một vòng lặp for để có được kết quả tương tự:
for index in 0..<elements.count {
let element = elements[index]
print("\(index): \(element)")
}
Hy vọng nó giúp.
for (index, element) in arrayOfValues.enumerate() {
// do something useful
}
hoặc với Swift 3 ...
for (index, element) in arrayOfValues.enumerated() {
// do something useful
}
Tuy nhiên, tôi thường sử dụng phép liệt kê kết hợp với bản đồ hoặc bộ lọc. Ví dụ với hoạt động trên một vài mảng.
Trong mảng này, tôi muốn lọc các phần tử lẻ hoặc thậm chí được lập chỉ mục và chuyển đổi chúng từ Ints thành Double. Vì vậy, enumerate()
giúp bạn lập chỉ mục và phần tử, sau đó bộ lọc kiểm tra chỉ mục và cuối cùng để loại bỏ bộ dữ liệu kết quả, tôi ánh xạ nó thành phần tử.
let evens = arrayOfValues.enumerate().filter({
(index: Int, element: Int) -> Bool in
return index % 2 == 0
}).map({ (_: Int, element: Int) -> Double in
return Double(element)
})
let odds = arrayOfValues.enumerate().filter({
(index: Int, element: Int) -> Bool in
return index % 2 != 0
}).map({ (_: Int, element: Int) -> Double in
return Double(element)
})
Sử dụng .enumerate()
các tác phẩm, nhưng nó không cung cấp chỉ mục thực sự của phần tử; nó chỉ cung cấp một Int bắt đầu bằng 0 và tăng thêm 1 cho mỗi phần tử liên tiếp. Điều này thường không liên quan, nhưng có khả năng xảy ra hành vi bất ngờ khi được sử dụng với ArraySlice
loại. Lấy mã sau:
let a = ["a", "b", "c", "d", "e"]
a.indices //=> 0..<5
let aSlice = a[1..<4] //=> ArraySlice with ["b", "c", "d"]
aSlice.indices //=> 1..<4
var test = [Int: String]()
for (index, element) in aSlice.enumerate() {
test[index] = element
}
test //=> [0: "b", 1: "c", 2: "d"] // indices presented as 0..<3, but they are actually 1..<4
test[0] == aSlice[0] // ERROR: out of bounds
Đó là một ví dụ hơi khó hiểu và nó không phải là vấn đề phổ biến trong thực tế nhưng tôi vẫn nghĩ rằng điều đó đáng để biết điều này có thể xảy ra.
it does not actually provide the true index of the element; it only provides an Int beginning with 0 and incrementing by 1 for each successive element
Vâng, đó là lý do tại sao nó được gọi là liệt kê . Ngoài ra, lát không phải là mảng, vì vậy không có gì ngạc nhiên khi nó hoạt động khác đi. Không có lỗi ở đây - mọi thứ đều do thiết kế. :)
filter
trước không?
Để hoàn thiện, bạn có thể chỉ cần lặp lại các chỉ số mảng của mình và sử dụng chỉ mục để truy cập phần tử ở chỉ mục tương ứng:
let list = [100,200,300,400,500]
for index in list.indices {
print("Element at:", index, " Value:", list[index])
}
Sử dụng forEach
list.indices.forEach {
print("Element at:", $0, " Value:", list[$0])
}
Sử dụng enumerated()
phương pháp thu thập . Lưu ý rằng nó trả về một bộ các bộ dữ liệu với offset
và element
:
for item in list.enumerated() {
print("Element at:", item.offset, " Value:", item.element)
}
sử dụng forEach:
list.enumerated().forEach {
print("Element at:", $0.offset, " Value:", $0.element)
}
Những người sẽ in
Phần tử tại: 0 Giá trị: 100
Phần tử tại: 1 Giá trị: 200
Phần tử tại: 2 Giá trị: 300
Phần tử tại: 3 Giá trị: 400
Phần tử tại: 4 Giá trị: 500
Nếu bạn cần chỉ mục mảng (không phải phần bù) và phần tử của nó, bạn có thể mở rộng Bộ sưu tập và tạo phương thức của riêng bạn để lấy các phần tử được lập chỉ mục:
extension Collection {
func indexedElements(body: ((index: Index, element: Element)) throws -> Void) rethrows {
var index = startIndex
for element in self {
try body((index,element))
formIndex(after: &index)
}
}
}
Một cách triển khai khả thi khác theo đề xuất của Alex là nén các chỉ số bộ sưu tập với các yếu tố của nó:
extension Collection {
func indexedElements(body: ((index: Index, element: Element)) throws -> Void) rethrows {
for element in zip(indices, self) { try body(element) }
}
}
Kiểm tra:
let list = ["100","200","300","400","500"]
list.dropFirst(2).indexedElements {
print("Index:", $0.index, "Element:", $0.element)
}
Điều này sẽ p [rint
Chỉ số: 2 Yếu tố: 300
Chỉ số: 3 yếu tố: 400
Chỉ số: 4 yếu tố: 500
enumeratedIndices
bằng cách lặp lại vớizip(self.indices, self)
for element in zip(indices, self) { try body(element) }
. Btw Tôi không thích cách đặt tên mà tôi đã chọn, indexedElements
có thể mô tả tốt hơn những gì nó làm
for
vòng lặp hoạt động, nhưng cũngzip(self.indices, self) .forEach(body)
forEach
thực hiện một vòng lặp phía sau hậu trường. Tôi thích giữ cho nó đơn giản github.com/apple/swift/blob/master/stdlib/public/core/ mẹo@inlinable public func forEach( _ body: (Element) throws -> Void ) rethrows { for element in self { try body(element) } } }
Xcode 8 và Swift 3: Array có thể được liệt kê bằng cách sử dụng tempArray.enumerated()
Thí dụ:
var someStrs = [String]()
someStrs.append("Apple")
someStrs.append("Amazon")
someStrs += ["Google"]
for (index, item) in someStrs.enumerated()
{
print("Value at index = \(index) is \(item)").
}
bảng điều khiển:
Value at index = 0 is Apple
Value at index = 1 is Amazon
Value at index = 2 is Google
Dành cho những ai muốn sử dụng forEach
.
Swift 4
extension Array {
func forEachWithIndex(_ body: (Int, Element) throws -> Void) rethrows {
try zip((startIndex ..< endIndex), self).forEach(body)
}
}
Hoặc là
array.enumerated().forEach { ... }
Đối với những gì bạn muốn làm, bạn nên sử dụng enumerated()
phương thức trên Mảng của bạn :
for (index, element) in list.enumerated() {
print("\(index) - \(element)")
}
Chúng tôi đã gọi hàm liệt kê để thực hiện điều này. giống
for (index, phần tử) trong mảng.enum Cả () {
// chỉ mục là chỉ mục của mảng
// phần tử là phần tử của mảng
}