배열에서 객체를 찾으십니까?


144

Swift에는 Underscore.js의 _.findWhere 와 같은 것이 있습니까?

유형의 구조체 배열이 있고 배열에 속성이 같은 T구조체 객체가 포함되어 있는지 확인하고 싶습니다 .nameFoo

사용하려고 find()하고 filter()기본 유형, 예와하지만, 그들은 단지 일 String또는 Int. Equitable프로토콜 또는 이와 유사한 것을 준수하지 않는 경우 오류가 발생 합니다.


이것은 당신이 찾고있는 것일 수 있습니다 : 배열에서 속성으로 객체 찾기 .
Martin R

왜있는 NSDictionary로 변환 및 검색하지
롱 보우

3
Swift 2.0에서 더 이상 find를 사용할 수 없다고 생각합니다. 1.2 코드를 Swift 2.0으로 변환하고 대신 IndexOf를 사용한다고 말했습니다.
스위프트 소다

답변:


91

FWIW, 사용자 정의 기능이나 확장 기능을 사용하지 않으려면 다음을 수행하십시오.

let array = [ .... ]
if let found = find(array.map({ $0.name }), "Foo") {
    let obj = array[found]
}

name먼저 배열을 생성 한 다음 배열을 생성 find합니다.

거대한 배열이있는 경우 다음을 수행 할 수 있습니다.

if let found = find(lazy(array).map({ $0.name }), "Foo") {
    let obj = array[found]
}

또는 아마도 :

if let found = find(lazy(array).map({ $0.name == "Foo" }), true) {
    let obj = array[found]
}

이것은 더 좋습니다. 전체적으로 더 단순 해 보이고 사용자 정의 함수를 만들 필요가 없으므로 이것을 답변으로 표시합니다.
Sahat Yalkabov

27
Swift 2.0부터 다음을 사용할 수 있습니다. array.indexOf ({$ 0.name == "Foo"})
tf.alves

73
Swift 3.0부터 객체가 필요한 경우 array.first (where : {$ 0.name == "Foo"})를 사용할 수 있습니다
Brett

$ 0.name에 문자열 "foo"가 포함되어 있는지 어떻게 확인할 수 있습니까? 답변은 정확히 일치하는 것입니다. 문자열이 필요합니다. 누구나 그것을위한 구문을 줄 수 있습니까
Azik Abdullah

290

스위프트 5

요소가 존재하는지 확인

if array.contains(where: {$0.name == "foo"}) {
   // it exists, do something
} else {
   //item could not be found
}

요소 가져 오기

if let foo = array.first(where: {$0.name == "foo"}) {
   // do something with foo
} else {
   // item could not be found
}

요소와 오프셋을 가져옵니다

if let foo = array.enumerated().first(where: {$0.element.name == "foo"}) {
   // do something with foo.offset and foo.element
} else {
   // item could not be found
}

오프셋 가져 오기

if let fooOffset = array.firstIndex(where: {$0.name == "foo"}) {
    // do something with fooOffset
} else {
    // item could not be found
}

6
멋진 스위프트 스타일 답변!
Zoltán

4
감사합니다 당신이 내이 내 코드를 많이 정리했다 보호기입니다
AD 진행

여러 조건을 확인하는 방법은 어레이 $0.name == "foo"가 하나의 작업을 $0.name == "boo" 수행하고 다른 작업을 수행
해야하는지

이것은 2020 년에 허용 된 답변보다 더 많은 도움이되었습니다.
Psiloc

$ 0.name에 문자열 "foo"가 포함되어 있는지 어떻게 확인할 수 있습니까? 누구나 그것을위한 구문을 줄 수 있습니까
Azik Abdullah

131

술어와 함께 index사용할 수 있는 방법을 사용할 수 있습니다 Array( 여기서 Apple 문서 참조 ).

func index(where predicate: (Element) throws -> Bool) rethrows -> Int?

구체적인 예를 들면 다음과 같습니다.

스위프트 5.0

if let i = array.firstIndex(where: { $0.name == "Foo" }) {
    return array[i]
}

스위프트 3.0

if let i = array.index(where: { $0.name == Foo }) {
    return array[i]
}

스위프트 2.0

if let i = array.indexOf({ $0.name == Foo }) {
    return array[i]
}

3
예, 이것은 swift 2.0에서만 작동합니다. 죄송합니다.
user3799504

@ user3799504 $ 0의 의미는 무엇입니까?
Pramod Tapaniya

클로저에 대한 첫 번째 인수는 $ 0입니다. 이 경우 self.generator.element 또는 배열의 각 요소를 나타냅니다. 참조하십시오 : developer.apple.com/library/ios/documentation/Swift/Conceptual/…
user3799504

1
스위프트 3은 어떻습니까?
adnako

38

스위프트 3

객체가 필요한 경우 다음을 사용하십시오.

array.first{$0.name == "Foo"}

( "Foo"라는 이름의 개체가 둘 이상 first있으면 지정되지 않은 순서에서 첫 번째 개체를 반환합니다)


감사합니다. 이것은 저쪽에 있어야합니다!
NerdyTherapist

3
감사합니다. 감사합니다. 다음과 같이 쓸 수도 있습니다 :array.first {$0.name == "Foo"}
Roland T.

2
Swift3 에서는 다음과 같아야 합니다.array.first(where: {$0.name == "Foo"})
Daniel

Daniel의 말에 따르면, 이것은 Swift 3에 대한 정답이며 최상의 답변입니다. map을 사용하지 말고이 목적으로 필터링하십시오. 그들은 전체 컬렉션을 반복하므로 엄청난 낭비가 될 수 있습니다.
Womble

20

배열에서 속성을 가진 객체 찾기에 표시된 것처럼 배열을 필터링 한 다음 첫 번째 요소를 선택할 수 있습니다 .

또는 사용자 정의 확장을 정의하십시오.

extension Array {

    // Returns the first element satisfying the predicate, or `nil`
    // if there is no matching element.
    func findFirstMatching<L : BooleanType>(predicate: T -> L) -> T? {
        for item in self {
            if predicate(item) {
                return item // found
            }
        }
        return nil // not found
    }
}

사용 예 :

struct T {
    var name : String
}

let array = [T(name: "bar"), T(name: "baz"), T(name: "foo")]

if let item = array.findFirstMatching( { $0.name == "foo" } ) {
    // item is the first matching array element
} else {
    // not found
}

Swift 3 에서는 기존 first(where:)방법을 사용할 수 있습니다 ( 주석에서 언급했듯이 ).

if let item = array.first(where: { $0.name == "foo" }) {
    // item is the first matching array element
} else {
    // not found
}

효율성 측면에서 이것은 어떻게 비교 array.lazy.filter( predicate ).first됩니까? 작은 배열에 대해 .lazy는 얼마나 효율적입니까?
Pat Niemeyer

@ PatNiemeyer : 모르겠습니다. 성능을 측정하고 비교해야합니다.
Martin R

@PatNiemeyer 차이가 크지 않더라도 위의 솔루션이 가장 효율적일 것입니다. 의 1. 복잡성은 filter항상 O(n)반면에 findFirstMatching그것은 최악의 시나리오 만의 (당신이 찾고있는 요소가 전혀 배열의 마지막 또는없는 경우). 2. 요청 filter된 요소를 findFirstMatching반환하는 동안 완전히 새로운 필터링 된 요소 배열을 만듭니다 .
0101

Swift 3에서는 비 프로토콜, 비 클래스 유형 'Bool'상속 되지 않은 유형 'T'의 확장 메소드 에서 상속 오류가 발생합니다 .
Isuru

@ Isuru : 그 대답은 꽤 오래되었고 이전 Swift 버전을 언급했습니다. Swift 3에서는 그 목적을 위해 더 이상 사용자 정의 확장 방법이 필요하지 않으므로 그에 따라 답변을 업데이트했습니다.
Martin R

20

스위프트 3.0

if let index = array.index(where: { $0.name == "Foo" }) {
    return array[index]
}

스위프트 2.1

swift 2.1에서는 객체 속성 필터링이 지원됩니다. 구조체 또는 클래스의 값을 기반으로 배열을 필터링 할 수 있습니다. 여기 예제가 있습니다.

for myObj in myObjList where myObj.name == "foo" {
 //object with name is foo
}

또는

for myObj in myObjList where myObj.Id > 10 {
 //objects with Id is greater than 10
}

9

스위프트 4 ,

필터 기능을 사용하여이를 달성하는 또 다른 방법은

if let object = elements.filter({ $0.title == "title" }).first {
    print("found")
} else {
    print("not found")
}

8

스위프트 3

Swift 3에서 index (where :)를 사용할 수 있습니다

func index(where predicate: @noescape Element throws -> Bool) rethrows -> Int?

if let i = theArray.index(where: {$0.name == "Foo"}) {
    return theArray[i]
}

조건을 충족시키는 배열 항목의 하위 목록의 색인을 찾을 수있는 신속한 방법 3이 $0.name == "Foo"있습니까?
Ahmed Khedr

3

스위프트 3

if yourArray.contains(item) {
   //item found, do what you want
}
else{
   //item not found 
   yourArray.append(item)
}

2

스위프트 2 이상

당신은 결합 할 수 indexOfmap한 줄에 "찾기 요소"함수를 작성 할 수 있습니다.

let array = [T(name: "foo"), T(name: "Foo"), T(name: "FOO")]
let foundValue = array.indexOf { $0.name == "Foo" }.map { array[$0] }
print(foundValue) // Prints "T(name: "Foo")"

filter+를 사용하면 first깔끔해 보이지만 filter배열의 모든 요소를 ​​평가합니다. indexOf+ map는 복잡해 보이지만 배열에서 첫 번째 일치 항목이 발견되면 평가가 중지됩니다. 두 가지 방법 모두 장단점이 있습니다.


1

사용 contains:

var yourItem:YourType!
if contains(yourArray, item){
    yourItem = item
}

또는 당신은 마틴이 코멘트에, 당신을 지적 무엇을 시도하고 줄 수있는 filter또 다른 시도 : 배열의 속성과 개체를 찾을 .


부울 만 반환합니까? 배열에 있는지 확인하는 것이 아니라 객체도 가져와야합니다.
Sahat Yalkabov

이것은 item배열의 항목과 동일한 유형 이라고 가정 합니다. 그러나 내가 가진 것은 단지 제목입니다 view.annotation.title. 이 제목으로 배열의 항목을 비교해야합니다.
Sahat Yalkabov

같은 것 if contains(yourArray, view.annotation.title) { // code goes here }.
Sahat Yalkabov

마틴은 의견에서 다른 방법을 보여주었습니다. 그가 제공 한 링크를 확인하십시오.
Christian

1

array.index (of : Any)에 액세스하는 또 다른 방법은 객체를 선언하는 것입니다.

import Foundation
class Model: NSObject {  }

1

Swift에 Lo-Dash 또는 Underscore.js 인 Dollar 를 사용하십시오 .

import Dollar

let found = $.find(array) { $0.name == "Foo" }

1

스위프트 3 :

Swifts 내장 기능을 사용하여 Array에서 사용자 정의 객체를 찾을 수 있습니다.

먼저 커스텀 객체가 Equatable protocol을 준수하는지 확인해야 합니다 .

class Person : Equatable { //<--- Add Equatable protocol
    let name: String
    var age: Int

    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

    //Add Equatable functionality:
    static func == (lhs: Person, rhs: Person) -> Bool {
        return (lhs.name == rhs.name)
    }
}

Equatable 기능이 객체에 추가되면 Swift는 이제 배열에서 사용할 수있는 추가 속성을 보여줍니다.

//create new array and populate with objects:
let p1 = Person(name: "Paul", age: 20)
let p2 = Person(name: "Mike", age: 22)
let p3 = Person(name: "Jane", age: 33)
var people = [Person]([p1,p2,p3])

//find index by object:
let index = people.index(of: p2)! //finds Index of Mike

//remove item by index:
people.remove(at: index) //removes Mike from array

1

스위프트 3의 경우

let index = array.index(where: {$0.name == "foo"})

0

예를 들어, 숫자 배열이 있다면 :

let numbers = [2, 4, 6, 8, 9, 10]

다음과 같이 첫 번째 홀수를 찾을 수 있습니다.

let firstOdd = numbers.index { $0 % 2 == 1 }

첫 번째 홀수 (9)가 인덱스 4에 있기 때문에 4를 선택적 정수로 다시 보냅니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.