Helpex - Trao đổi & giúp đỡ Đăng nhập
29

Tôi đang cố gắng giảm bớt một mảng Bools bằng cách áp dụng toán tử logic OR ( ||) bằng cách sử dụng mã sau, tuy nhiên tôi gặp lỗi:

func reduceBools(values: [Bool]) -> Bool {
    return values.reduce(false, combine: ||)
}

Tham chiếu không rõ ràng đến thành viên '||'

Tương tự đối với các số nguyên, mã hoạt động giống như một sự quyến rũ.

func reduceInts(values: [Int]) -> Int {
    return values.reduce(0, combine: +)
}

Tôi đã có thể làm cho nó hoạt động bằng cách thêm một ||hàm (mã bên dưới) hoặc sử dụng một hàm { $0 || $1 }đóng nhưng tôi không thích những cách tiếp cận này và tôi muốn chỉ cần chuyển toán tử.

func ||(lhs: Bool, rhs: Bool) -> Bool {
    return lhs || rhs
}

Điều tương tự cũng xảy ra đối với toán tử logic AND ( &&).

Làm thế nào tôi có thể làm cho nó hoạt động mà không sử dụng hack ở trên?

29 hữu ích 5 bình luận 7.8k xem chia sẻ
36

Để thay thế, bạn có thể sử dụng cách tiếp cận sau

// ||
func reduceBoolsOr(values: [Bool]) -> Bool {
    return values.contains(true)
}

// &&
func reduceBoolsAnd(values: [Bool]) -> Bool {
    return !values.contains(false)
}

Lưu ý rằng .reduce đi kèm với một chi phí . Nếu kết quả cuối cùng là tầm quan trọng của câu hỏi của bạn (thay vì hỏi về hành vi không mong đợi của ||và các &&toán tử trong ngữ cảnh này), thì có lẽ cách tiếp cận thực dụng ở trên có thể hữu ích, ngay cả khi nó không thực sự làm giảm mảng, tuy nhiên sản xuất kết quả tương tự do tính chất đơn giản của kiểu boolean.

36 hữu ích 2 bình luận chia sẻ
6

Cách tiếp cận sau sẽ hiệu quả

values.reduce(false) { $0 || $1 }
6 hữu ích 0 bình luận chia sẻ
6

Swift 4.2+ / Xcode 10.0+

Trong các phiên bản hiện đại của SwiftallSatisfy chức năng, trong đó kiểm tra tất cả các yếu tố để đáp ứng một số quy tắc.


Trong trường hợp của OP:

values.allSatisfy { $0 }
6 hữu ích 0 bình luận chia sẻ
2

Tham chiếu không rõ ràng đến thành viên '||' có nghĩa là có nhiều hơn một ứng cử viên có thể có, mà trình biên dịch không thể chọn. Trong trường hợp của bạn, đó là

public func ||<T : BooleanType, U : BooleanType>(lhs: T, @autoclosure rhs: () throws -> U) rethrows -> Bool

public func ||<T : BooleanType>(lhs: T, @autoclosure rhs: () throws -> Bool) rethrows -> Bool

có lẽ 'hack' của bạn bằng cách sử dụng a { $0 || $1 }là giải pháp tốt nhất ở đây.

2 hữu ích 1 bình luận chia sẻ
2

Điều này xảy ra do ngữ nghĩa đóng Swifts. Nó lấy đối số của bạn và áp dụng chức năng cho chúng, bỏ qua tên đối số.

protocol Numeric {
    ...
    public static func +(lhs: Self, rhs: Self) -> Self
    ...
}

Ví dụ với Ints, bạn sẽ chuyển (Int, Int) vào một hàm đóng và + trong giao thức Numeric mong đợi chính xác hai int để tính tổng chúng.

Đó là lý do tại sao mã như dưới đây hoạt động tốt

[1, 2, 3, 4].reduce(0, +)

Bởi vì bạn chỉ lấy 2 int và hàm áp dụng, chỉ cần hai int. Nếu bạn viết hàm của riêng mình, chỉ cần hai đối số, nó cũng sẽ hoạt động.

func myOwnAwesomeFunc<T: Numeric>(a: T, b: T) -> T { in
    return 1 // production ready
}

[1, 2, 3, 4].reduce(0, myOwnAwesomeFunc) // prints 1

Tốt cho đến nay. Nhưng tại sao chúng ta không thể viết

[true, false, true].reduce(false, ||) // yields Cannot invoke 'reduce' 
// with an argument list of type 
// '(Bool, (Bool, @autoclosure () throws -> Bool) throws -> Bool)'

Đó là bởi vì toán tử này nhận bool và một bao đóng, trả về bool. Không bool, đóng cửa! Nhưng nếu nó là như thế này, tại sao chúng ta không viết true || { false }()? Đó là bởi vì @autoclosure, nơi chăm sóc các dấu ngoặc nhọn cho chúng ta.

Câu hỏi chính, tại sao nó được triển khai theo cách này, vì vậy chúng tôi không thể sử dụng cú pháp đóng ngắn tay tuyệt vời của Swifts với boolean? Idk

2 hữu ích 2 bình luận chia sẻ
0

Đây là một cách tiếp cận khác, tôi đã sửa đổi hàm ReduceBools để lấy toán tử làm tham số -

typealias LogicalOperator = ((Bool, @autoclosure () throws -> Bool) throws -> Bool)

func reduceBools(values: [Bool], combine: LogicalOperator) -> Bool {
    var started: Bool = false
    return values.reduce(into: true, { (result, value) in
        result = started ? try! combine(result, value) : value // obviously up to you how you'd handle the try/catch
        started = true
    })
}

let bools = [true, false, false, true]

let result1 = self.reduceBools(values: bools, combine: ||)
print(result1) // prints true

let result2 = self.reduceBools(values: bools, combine: &&)
print(result2) // prints false

Hoặc nó có thể hữu ích hơn như một phần mở rộng của Trình tự -

extension Sequence where Element == Bool {

    func reduce(_ combine: LogicalOperator) -> Bool {
        var started: Bool = false
        return self.reduce(into: true, { (result, value) in
            result = started ? try! combine(result, value) : value
            started = true
        })
    }
}

print(bools.reduce(||)) // prints true
0 hữu ích 0 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ ios swift swift2 closures logical-operators , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading