सरणी में एक वस्तु का पता लगाएं?


144

क्या Swift में Underscore.js में _.find जैसी कोई चीज़ है ?

मेरे पास प्रकार की संरचनाओं की एक सरणी है Tऔर यह जांचना चाहूंगा कि क्या सरणी में एक संरचनात्मक वस्तु है जिसकी nameसंपत्ति के बराबर है Foo

उपयोग करने की कोशिश की find()और filter()वे केवल आदिम प्रकार, जैसे Stringया के साथ काम करते हैं IntEquitableप्रोटोकॉल या इस तरह से कुछ नहीं करने के बारे में एक त्रुटि फेंकता है।


यह वही हो सकता है जिसे आप ढूंढ रहे हैं: एरे में संपत्ति के साथ ऑब्जेक्ट ढूंढें
मार्टिन आर

क्यों NSDictionary में परिवर्तित नहीं और के लिए खोज
धनुष

3
मेरा मानना ​​है कि स्विफ्ट 2.0 अब उपलब्ध नहीं है। मैं स्विफ्ट 2.0 को कुछ 1.2 कोड में परिवर्तित कर रहा था और उसने इसके बजाय 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]
}

यह और भी बेहतर है। मैं इसे उत्तर के रूप में चिह्नित करूंगा क्योंकि यह समग्र रूप से सरल दिखता है और इसे कस्टम फ़ंक्शन बनाने की आवश्यकता नहीं है।
सहत यल्कबोव

27
स्विफ्ट 2.0 के अनुसार आप उपयोग कर सकते हैं: array.indexOf ({$ 0.name == "फू"})
tf.alves

73
स्विफ्ट 3.0 के रूप में आप उपयोग कर सकते हैं: array.first (जहां: {$ 0.name == "फू"}) यदि आपको ऑब्जेक्ट की आवश्यकता है
ब्रेट

मैं $ 0.name कैसे जांच सकता हूं जिसमें स्ट्रिंग "फू" शामिल है? उत्तर सटीक मिलान के बारे में हैं। मुझे स्ट्रिंग की आवश्यकता है। क्या कोई इसके लिए वाक्य रचना दे सकता है
अज़िक अब्दुल्ला

289

स्विफ्ट 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
अच्छा स्विफ्ट-शैली का जवाब!
ज़ोल्टन

4
धन्यवाद आप मेरे सेवर हैं इसने मेरे कोड को बहुत साफ किया है
विज्ञापन प्रगति

कैसे कई स्थितियों की जाँच करने के लिए मुझे लगता है कि अगर $0.name == "foo"एक ऑपरेशन $0.name == "boo" करते हैं और एक और ऑपरेशन करना है
मिधुन नारायण

इससे मुझे 2020 में स्वीकृत जवाब से ज्यादा मदद मिली।
Psiloc

मैं $ 0.name कैसे जांच सकता हूं जिसमें स्ट्रिंग "फू" शामिल है? क्या कोई इसके लिए वाक्य रचना दे सकता है
अज़िक अब्दुल्ला

131

आप एक विधेय के साथ indexउपलब्ध विधि का उपयोग कर सकते हैं Array( एप्पल के दस्तावेज यहां देखें )।

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
हां यह केवल स्विफ्ट 2.0 के साथ काम करता है। सॉरी इसका जिक्र करना चाहिए था।
user3799504 18

@ user3799504 $ 0 का अर्थ?
प्रमोद तपनिया

$ 0 बंद होने के पहले तर्क के लिए आशुलिपि है। इस मामले में यह self.generator.element या सरणी के प्रत्येक तत्व को संदर्भित करता है। कृपया देखें: developer.apple.com/library/ios/documentation/Swift/Conceptual/…
user3799504

1
स्विफ्ट 3 के बारे में कैसे?
अडंको ३१'१६

38

स्विफ्ट 3

यदि आपको वस्तु के उपयोग की आवश्यकता है:

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

(यदि आपके पास "फू" नामक एक से अधिक ऑब्जेक्ट है तो firstअनिर्दिष्ट आदेश से पहली वस्तु वापस कर देंगे)


इसके लिए शुक्रिया। यह वहाँ रास्ता होना चाहिए!
NerdyTherapist 21

3
यह अच्छा है, धन्यवाद! इसे इस तरह भी लिखा जा सकता है:array.first {$0.name == "Foo"}
रोलैंड टी।

2
में Swift3 यह होना चाहिएarray.first(where: {$0.name == "Foo"})
डैनियल

डैनियल के नोट के साथ, यह स्विफ्ट के लिए सही, सर्वश्रेष्ठ उत्तर है। इस उद्देश्य के लिए मानचित्र, फ़िल्टर का उपयोग न करें; वे पूरे संग्रह पर पुनरावृति करते हैं, जो बेहद बेकार हो सकता है।
वूमबल

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
}

में स्विफ्ट 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 कितना कुशल है?
पैट नीमरियर

@PatNiemeyer: मुझे नहीं पता, आपको प्रदर्शन को मापना होगा और तुलना करनी होगी।
मार्टिन आर

@PatNiemeyer उपरोक्त समाधान निश्चित रूप से अधिक कुशल होगा भले ही अंतर संभवतः बड़ा नहीं होगा। 1. की जटिलता filterहमेशा है O(n)जबकि findFirstMatchingयह केवल सबसे खराब परिदृश्य में है (जब आप जिस तत्व की तलाश कर रहे हैं वह आखिरी है या सरणी में बिल्कुल नहीं है)। 2. filterफ़िल्टर किए गए तत्वों की एक पूरी तरह से नई सरणी बनाता है जबकि findFirstMatchingबस अनुरोधित तत्व देता है।
0101

स्विफ्ट 3 में, मुझे गैर-प्रोटोकॉल, गैर-श्रेणी के प्रकार 'बूल' और इस विस्तार पद्धति के लिए अघोषित प्रकार 'टी' के उपयोग से त्रुटियों का सामना करना पड़ रहा है
इसरू

@ इस्ुरु: वह उत्तर काफी पुराना था और एक पुराने स्विफ्ट संस्करण के लिए संदर्भित था। स्विफ्ट 3 में अब आपको उस उद्देश्य के लिए कस्टम एक्सटेंशन विधि की आवश्यकता नहीं है, मैंने उसके अनुसार उत्तर अपडेट कर दिया है।
मार्टिन आर।

20

स्विफ्ट 3.0

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

स्विफ्ट 2.1

ऑब्जेक्ट प्रॉपर्टी में फ़िल्टरिंग अब स्विफ्ट 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

आप सूचकांक का उपयोग कर सकते हैं (जहां स्विफ्ट 3 में :)

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"?
अहमद खेदर

3

स्विफ्ट 3

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

2

स्विफ्ट 2 या बाद में

आप एक लाइन में "एलीमेंट एलीमेंट" फ़ंक्शन को जोड़ सकते हैं indexOfऔर mapलिख सकते हैं ।

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एक और कोशिश दें: एरे में संपत्ति के साथ वस्तु खोजें


क्या वह केवल एक बूलियन लौटाएगा? मुझे ऑब्जेक्ट भी प्राप्त करने की आवश्यकता है, न कि केवल यह जांचें कि क्या सरणी में है।
सहत यल्कबोव

यह मान itemसरणी में आइटम के समान प्रकार का है। हालाँकि, मेरे पास केवल एक शीर्षक है view.annotation.title। मुझे इस शीर्षक द्वारा सरणी में आइटम की तुलना करने की आवश्यकता है।
सहत यल्कबोव

कुछ इस तरह if contains(yourArray, view.annotation.title) { // code goes here }
सहत यल्कबोव

मार्टिन ने आपको टिप्पणियों में एक और तरीका दिखाया। उसके द्वारा दिए गए लिंक की जाँच करें।
क्रिश्चियन

1

Array.index (में: कोई भी) तक पहुंचने का एक और तरीका है अपनी वस्तु की घोषणा करना

import Foundation
class Model: NSObject {  }


1

स्विफ्ट 3:

आप सरणी में कस्टम ऑब्जेक्ट खोजने के लिए कार्यक्षमता में निर्मित स्विफ्ट का उपयोग कर सकते हैं।

सबसे पहले आपको यह सुनिश्चित करना चाहिए कि आपकी कस्टम ऑब्जेक्ट इसके अनुरूप है: इक्विटेबल प्रोटोकॉल

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)
    }
}

आपकी वस्तु में समतुल्य कार्यक्षमता के साथ, स्विफ्ट अब आपको अतिरिक्त गुण दिखाएगा जिसका उपयोग आप किसी सरणी में कर सकते हैं:

//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


0

उदाहरण के लिए, यदि हमारे पास संख्याओं की एक सरणी है:

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

हम इस तरह की पहली विषम संख्या पा सकते हैं:

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

यह 4 को वैकल्पिक पूर्णांक के रूप में वापस भेजेगा, क्योंकि पहली विषम संख्या (9) सूचकांक चार पर है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.