Safeচ্ছিক বাঁধাইয়ের মাধ্যমে সুইফটে নিরাপদ (সীমাবদ্ধ-পরীক্ষা করা) অ্যারে লুকআপ?


271

যদি আমার সুইফটে একটি অ্যারে থাকে এবং সীমার বাইরে থাকা একটি সূচকটি অ্যাক্সেস করার চেষ্টা করি তবে একটি আশ্চর্যজনক রানটাইম ত্রুটি রয়েছে:

var str = ["Apple", "Banana", "Coconut"]

str[0] // "Apple"
str[3] // EXC_BAD_INSTRUCTION

যাইহোক, আমি সুইফট যে সমস্ত alচ্ছিক শৃঙ্খলা এবং সুরক্ষা নিয়ে আসে তা নিয়ে ভাবতাম , এমন কিছু করা তুচ্ছ হবে:

let theIndex = 3
if let nonexistent = str[theIndex] { // Bounds check + Lookup
    print(nonexistent)
    ...do other things with nonexistent...
}

পরিবর্তে:

let theIndex = 3
if (theIndex < str.count) {         // Bounds check
    let nonexistent = str[theIndex] // Lookup
    print(nonexistent)   
    ...do other things with nonexistent... 
}

তবে এটি নয় - ifসূচকের চেয়ে কম কিনা তা যাচাই করতে এবং নিশ্চিত করতে আমাকে 'অল' বিবৃতি ব্যবহার করতে হবে str.count

আমি আমার নিজস্ব subscript()বাস্তবায়ন যোগ করার চেষ্টা করেছি , তবে কীভাবে মূল বাস্তবায়নে কলটি পাস করতে হবে বা সাবস্ক্রিপ্ট নোটেশন ব্যবহার না করে আইটেমগুলিতে (সূচী-ভিত্তিক) অ্যাক্সেস করবেন তা নিশ্চিত নই:

extension Array {
    subscript(var index: Int) -> AnyObject? {
        if index >= self.count {
            NSLog("Womp!")
            return nil
        }
        return ... // What?
    }
}

2
আমি বুঝতে পারি এটি সামান্য ওটি, তবে আমিও মনে করি এটি ভাল লাগবে যদি তালিকাসহ কোনও ধরণের বাউন্ড চেক সম্পাদনের জন্য সুইফ্টের স্পষ্ট বাক্য গঠন থাকে। ইতিমধ্যে এটির জন্য আমাদের কাছে একটি উপযুক্ত কীওয়ার্ড রয়েছে So সুতরাং উদাহরণস্বরূপ, যদি এক্স ইন (1,2,7) ... অথবা যদি মাইআরায় এক্স হয়
মরি মার্কোভিটজ

উত্তর:


652

অ্যালেক্সের উত্তরের প্রশ্নের জন্য ভাল পরামর্শ এবং সমাধান রয়েছে, তবে আমি এই কার্যকারিতাটি বাস্তবায়নের একটি দুর্দান্ত পদ্ধতিতে হোঁচট খাচ্ছি:

সুইফট ৩.২ এবং আরও নতুন

extension Collection {

    /// Returns the element at the specified index if it is within bounds, otherwise nil.
    subscript (safe index: Index) -> Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

সুইফট 3.0 এবং 3.1

extension Collection where Indices.Iterator.Element == Index {

    /// Returns the element at the specified index if it is within bounds, otherwise nil.
    subscript (safe index: Index) -> Generator.Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

হামিশকে সুইফট 3-র সমাধান নিয়ে আসার জন্য ক্রেডিট ।

সুইফট 2

extension CollectionType {

    /// Returns the element at the specified index if it is within bounds, otherwise nil.
    subscript (safe index: Index) -> Generator.Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

উদাহরণ

let array = [1, 2, 3]

for index in -20...20 {
    if let item = array[safe: index] {
        print(item)
    }
}

45
আমি মনে করি এটি অবশ্যই মনোযোগের দাবিদার - দুর্দান্ত কাজ। safe:পার্থক্যটি নিশ্চিত করতে আমি অন্তর্ভুক্ত প্যারামিটারের নামটি পছন্দ করি ।
ক্রেগ ওটিস

11
সুইফট 2 (এক্সকোড 7) হিসাবে এটির জন্য কিছুটা সাম্প্রতিক প্রয়োজন:return self.indices ~= index ? self[index] : nil;
টিম

7
সুইফট 3 সংস্করণ সম্পর্কিত: সম্ভবত কোনও কোণে-কেবল-প্রম্পট, তবে তবুও একটি প্রম্পট: এমন কিছু ক্ষেত্রে রয়েছে যেখানে উপরের "নিরাপদ" সাবস্ক্রিপ্ট সংস্করণটি নিরাপদ নয় (যেখানে সুইফট 2 সংস্করণটি ছিল): যে Collectionধরণের Indicesক্ষেত্রে স্বচ্ছ নয় যেমন জন্য Setদৃষ্টান্ত, আমরা ইনডেক্স (দ্বারা একটি সেট উপাদান অ্যাক্সেস করতে হলে SetIndex<Element>), আমরা সূচকের হয় যে জন্য রানটাইম ব্যতিক্রমের চালাতে পারেন >= startIndexএবং < endIndex, যে ক্ষেত্রে নিরাপদ সাবস্ক্রিপ্ট ব্যর্থ (দেখুন উদাঃ এই কল্পিত উদাহরণ )।
dfri

12
সতর্কবার্তা! এইভাবে অ্যারে পরীক্ষা করা ব্যয়বহুল হতে পারে। containsপদ্ধতি সব সূচকের এইভাবে এই একটি হে (ঢ) উপার্জন মাধ্যমে পুনরুক্তি হবে। আরও ভাল উপায় হ'ল সূচিটি ব্যবহার করা এবং গণ্ডিগুলি পরীক্ষা করা count
স্টিফান ভাসিলজেভিক

6
সূচকের উৎপাদিত এবং তাদের উপর iterating প্রতিরোধ করার জন্য (হে (ঢ)), এটা ব্যবহার তুলনা ভালো (হে (1)): return index >= startIndex && index < endIndex ? self[index] : nil Collectionধরনের startIndex, endIndexযা Comparable। অবশ্যই, এটি কিছু অদ্ভুত সংগ্রহগুলির জন্য কাজ করবে না, উদাহরণস্বরূপ, মাঝখানে সূচকগুলি নেই, এর সাথে সমাধান indicesআরও সাধারণ।
zubko

57

আপনি যদি সত্যই এই আচরণটি চান, এটির মতো গন্ধ লাগে যে আপনি অ্যারের পরিবর্তে অভিধান চান। nilঅনুপস্থিত কীগুলি অ্যাক্সেস করার সময় অভিধানগুলি ফিরে আসে, যা বোঝায় যে কারণ কোনও অভিধানে কোনও কী উপস্থিত রয়েছে কিনা তা জানা খুব শক্ত কারণ যে কীগুলি যে কোনও কিছু হতে পারে, যেখানে অ্যারেতে কীটি অবশ্যই একরকমের মধ্যে থাকা উচিত : 0থেকে count। এবং এই ব্যাপ্তিটি দিয়ে পুনরাবৃত্তি করা অবিশ্বাস্যরকম সাধারণ, যেখানে আপনি লুপের প্রতিটি পুনরাবৃত্তির সত্যিকারের মান রাখতে পারবেন তা নিশ্চিত

আমি মনে করি যে এটি এটি কাজ করে না তার কারণটি হ'ল সুইফট বিকাশকারীদের তৈরি করা একটি নকশা পছন্দ। আপনার উদাহরণ নিন:

var fruits: [String] = ["Apple", "Banana", "Coconut"]
var str: String = "I ate a \( fruits[0] )"

আপনি যদি ইতিমধ্যে জানেন যে সূচিটি বিদ্যমান, আপনি বেশিরভাগ ক্ষেত্রে যেমন আপনি অ্যারে ব্যবহার করেন তবে এই কোডটি দুর্দান্ত। যাইহোক, যদি একটি সাবস্ক্রিপ্ট অ্যাক্সেস সম্ভবত আসতে পারে nilতারপর আপনি রিটার্ন টাইপ পরিবর্তিত হয়েছে এর Array'র subscriptপদ্ধতি একটি ঐচ্ছিক যাবে। এটি আপনার কোডকে এতে পরিবর্তন করে:

var fruits: [String] = ["Apple", "Banana", "Coconut"]
var str: String = "I ate a \( fruits[0]! )"
//                                     ^ Added

যার অর্থ আপনি যখনই কোনও অ্যারের মাধ্যমে পুনরুক্তি করেছেন তখন প্রতিবার একটি wচ্ছিক আনইনপ্যাপ করতে হবে, বা কোনও পরিচিত সূচক দিয়ে অন্য কিছু করেছেন, খুব কমই আপনার সীমাবদ্ধতার সূচকটি অ্যাক্সেস হতে পারে। সীমানা সূচকগুলি অ্যাক্সেস করার সময় রানটাইম ব্যতিক্রম ব্যয় করে সুইফ্ট ডিজাইনাররা বিকল্পগুলির কম আনারপ্যাটিংয়ের বিকল্পটি বেছে নিয়েছিলেন। এবং nilকোথাও কোথাও আপনার ডেটাতে আপনি প্রত্যাশা করেননি এমন কারণে যুক্তিযুক্ত ত্রুটির জন্য ক্র্যাশটি পছন্দনীয় ।

এবং আমি তাদের সাথে একমত। সুতরাং আপনি ডিফল্ট Arrayবাস্তবায়ন পরিবর্তন করবেন না কারণ আপনি অ্যারে থেকে একটি অ-alচ্ছিক মান প্রত্যাশা করে এমন সমস্ত কোড ভঙ্গ করবেন।

পরিবর্তে, আপনি সাবক্লাস করতে পারেন এবং একটি return Arrayচ্ছিক subscriptফিরে আসতে ওভাররাইড করতে পারেন। অথবা, আরও ব্যবহারিকভাবে, আপনি Arrayএমন কোনও সাবস্ক্রিপ্ট পদ্ধতি ব্যবহার করতে পারেন যা এটি করে।

extension Array {

    // Safely lookup an index that might be out of bounds,
    // returning nil if it does not exist
    func get(index: Int) -> T? {
        if 0 <= index && index < count {
            return self[index]
        } else {
            return nil
        }
    }
}

var fruits: [String] = ["Apple", "Banana", "Coconut"]
if let fruit = fruits.get(1) {
    print("I ate a \( fruit )")
    // I ate a Banana
}

if let fruit = fruits.get(3) {
    print("I ate a \( fruit )")
    // never runs, get returned nil
}

সুইফট 3 আপডেট

func get(index: Int) ->T? দ্বারা প্রতিস্থাপন করা প্রয়োজন func get(index: Int) ->Element?


2
রিটার্নের ধরণটিকে subscript()anচ্ছিকভাবে পরিবর্তন করার সাথে সমস্যাটি উল্লেখ করার জন্য +1 (এবং স্বীকার করুন) - এটিই ছিল ডিফল্ট আচরণকে ওভাররাইড করার ক্ষেত্রে প্রধান প্রাথমিক প্রতিবন্ধক। (আমি আসলে এটি একেবারেই কাজ করতে পারি না ) আমি কোনও get()এক্সটেনশন পদ্ধতি লিখতে এড়িয়ে যাচ্ছিলাম যা অন্য পরিস্থিতিতে (ওবজ-সি বিভাগসমূহ, কেউ?) এর সুস্পষ্ট পছন্দ তবে এর get(চেয়ে বড় নয় [, এবং এটি তৈরি করে সাফ করুন যে আচরণটি অন্য বিকাশকারীদের সুইফট সাবস্ক্রিপ্ট অপারেটরের থেকে আশা করা থেকে আলাদা হতে পারে। ধন্যবাদ!
ক্রেগ ওটিস

3
এটিকে আরও খাটো করার জন্য, আমি ();) এ ব্যবহার করি ধন্যবাদ!
হিউউউ

7
সুইফট ২.০ Tহিসাবে নতুন নামকরণ করা হয়েছে Element। কেবল একটি বন্ধুত্বপূর্ণ অনুস্মারক :)
স্টাস ঝুকভস্কি

3
এই আলোচনার যোগ করার জন্য, বাউন্ডস চেকিং বিকল্পের ফেরত দেওয়ার জন্য সুইফটে বেকড না হওয়ার আরেকটি কারণ হ'ল বাহ্যিক nilসীমানা সূচক থেকে ব্যতিক্রমের পরিবর্তে ফিরে আসা অস্পষ্ট হবে। যেহেতু যেমন Array<String?>সংগ্রহের একটি বৈধ সদস্য হিসাবে শূন্যস্থানও ফিরে আসতে পারে, আপনি সেই দুটি ক্ষেত্রে পার্থক্য করতে পারবেন না। যদি আপনার নিজের সংগ্রহের ধরণ থাকে তবে আপনি জানেন যে কোনও nilমান কখনই ফেরত করতে পারবেন না , এটি আবেদনের প্রাসঙ্গিক, তবে আপনি এই পোস্টে উত্তর হিসাবে নিরাপদ সীমানা যাচাইয়ের জন্য সুইফট প্রসারিত করতে পারেন।
হারুন

সুন্দরভাবে কাজ করে
kamyFC

20

নিকিতা কুকুশকিনের উত্তরটি তৈরি করতে, কখনও কখনও আপনাকে নিরাপদে সূচি নির্ধারণের পাশাপাশি সেগুলি থেকে পড়ার প্রয়োজন হয়, অর্থাৎ

myArray[safe: badIndex] = newValue

সুতরাং নিকিতার উত্তরের একটি আপডেট এখানে রয়েছে (সুইফট ৩.২) যা নিরাপদে: প্যারামিটারের নাম যুক্ত করে পরিবর্তনীয় অ্যারে সূচকগুলিতে নিরাপদে লেখার অনুমতি দেয়।

extension Collection {
    /// Returns the element at the specified index iff it is within bounds, otherwise nil.
    subscript(safe index: Index) -> Element? {
        return indices.contains(index) ? self[ index] : nil
    }
}

extension MutableCollection {
    subscript(safe index: Index) -> Element? {
        get {
            return indices.contains(index) ? self[ index] : nil
        }

        set(newValue) {
            if let newValue = newValue, indices.contains(index) {
                self[ index] = newValue
            }
        }
    }
}

2
চরম আন্ডাররেটেড উত্তর! টোট এটি সঠিক উপায়!
রিড করুন

14

সুইফট 2 এ বৈধ

যদিও এর আগেই প্রচুর উত্তর দেওয়া হয়েছে, আমি সুইফট প্রোগ্রামিংয়ের ফ্যাশনটি কোথায় চলছে তার সাথে সামঞ্জস্য রেখে আরও একটি উত্তর উপস্থাপন করতে চাই, যা ক্রাস্টির ভাষায় রয়েছে: "থিংক protocolএস"

• আমরা কী করতে চাই?
- কেবলমাত্র নিরাপদ থাকাকালীন কোনও Arrayপ্রদত্ত সূচকের একটি উপাদান পান , এবং nilঅন্যথায়
function এই কার্যকারিতাটির ভিত্তিটি এর বাস্তবায়নের ভিত্তিতে কী হওয়া উচিত?
- Array subscripting
it কোথা থেকে এই বৈশিষ্ট্যটি পাওয়া যায়?
- তার সংজ্ঞা struct Arrayমধ্যে Swiftমডিউল এটা আছে
• আর কিছু জেনেরিক / বিমূর্ত?
- এটি গ্রহণ করে protocol CollectionTypeযা এটিও নিশ্চিত করে
• এর চেয়ে বেশি জেনেরিক / বিমূর্ত কিছুই নেই?
- এটি protocol Indexableপাশাপাশি গ্রহণ করে ...
up হ্যাঁ, আমরা করতে পারি এমন সেরা শোনাচ্ছে। আমরা কি আমাদের চাইলে এই বৈশিষ্ট্যটি বাড়িয়ে দিতে পারি?
- তবে আমাদের খুব সীমাবদ্ধ প্রকার (না Int) এবং বৈশিষ্ট্য (নেই)count) এখন কাজ!
• এটি যথেষ্ট হবে। সুইফটের স্ট্ডলিব বেশ ভালভাবে সম্পন্ন হয়েছে;)

extension Indexable {
    public subscript(safe safeIndex: Index) -> _Element? {
        return safeIndex.distanceTo(endIndex) > 0 ? self[safeIndex] : nil
    }
}

।: সত্য নয়, তবে এটি ধারণা দেয়


2
একজন সুইফ্ট নবাগত হিসাবে আমি এই উত্তরটি বুঝতে পারি না। শেষে কোডটি কী উপস্থাপন করে? এটি কি একটি সমাধান, এবং যদি তাই হয় তবে আমি আসলে এটি কীভাবে ব্যবহার করব?
টমাস টেম্পেলম্যান

3
দুঃখিত, এই উত্তরটি সুইফট 3 এর জন্য আর বৈধ নয়, তবে প্রক্রিয়াটি অবশ্যই certainly পার্থক্যটি হ'ল এখন আপনার Collectionসম্ভবত থামানো উচিত :)
DeFrenZ

11
extension Array {
    subscript (safe index: Index) -> Element? {
        return 0 <= index && index < count ? self[index] : nil
    }
}
  • ও (1) পারফরম্যান্স
  • নিরাপদ টাইপ করুন
  • [মাইটাইপ?] এর বিকল্পগুলির সাথে সঠিকভাবে ডিল করে (মাইটাইপ ফিরিয়ে দেয় ??, যা উভয় স্তরেই মোড়ানো যায়)
  • সেটগুলির জন্য সমস্যা তৈরি করে না
  • সংক্ষিপ্ত কোড

আমি আপনার জন্য দৌড়েছি এমন কিছু পরীক্ষা এখানে রইল:

let itms: [Int?] = [0, nil]
let a = itms[safe: 0] // 0 : Int??
a ?? 5 // 0 : Int?
let b = itms[safe: 1] // nil : Int??
b ?? 5 // nil : Int?
let c = itms[safe: 2] // nil : Int??
c ?? 5 // 5 : Int?

10
  • অ্যারেগুলি শূন্য মানগুলি সংরক্ষণ করতে পারে, তাই যদি অ্যারে [সূচক] কলটি সীমা ছাড়িয়ে যায় তবে কোনও শূন্য ফেরত দেওয়া কোনও অর্থবোধ করে না।
  • যেহেতু আমরা জানি না যে কোনও ব্যবহারকারী কীভাবে সীমাবদ্ধতার সমস্যাগুলি সমাধান করতে চান, এটি কাস্টম অপারেটরগুলি ব্যবহার করার কোনও মানে হয় না।
  • এর বিপরীতে, মোড়কজাত অবজেক্টগুলির জন্য traditionalতিহ্যবাহী নিয়ন্ত্রণ প্রবাহ ব্যবহার করুন এবং প্রকারের সুরক্ষা নিশ্চিত করুন।

যদি সূচী = অ্যারে। শেইকইন্ডেক্সফোরসফটিটি (সূচী: আন্ত)

  let item = array[safeIndex: index] 

যদি সূচী = অ্যারে। শেইকইন্ডেক্সফোরসফটিটি (সূচী: আন্ত)

  array[safeIndex: safeIndex] = myObject
extension Array {

    @warn_unused_result public func checkIndexForSafety(index: Int) -> SafeIndex? {

        if indices.contains(index) {

            // wrap index number in object, so can ensure type safety
            return SafeIndex(indexNumber: index)

        } else {
            return nil
        }
    }

    subscript(index:SafeIndex) -> Element {

        get {
            return self[index.indexNumber]
        }

        set {
            self[index.indexNumber] = newValue
        }
    }

    // second version of same subscript, but with different method signature, allowing user to highlight using safe index
    subscript(safeIndex index:SafeIndex) -> Element {

        get {
            return self[index.indexNumber]
        }

        set {
            self[index.indexNumber] = newValue
        }
    }

}

public class SafeIndex {

    var indexNumber:Int

    init(indexNumber:Int){
        self.indexNumber = indexNumber
    }
}

1
আকর্ষণীয় পদ্ধতির। কোন কারণ SafeIndexএকটি শ্রেণি না একটি কাঠামো?
stef

8

সুইফট 4

যারা আরও বেশি traditionalতিহ্যগত বাক্য গঠন পছন্দ করেন তাদের জন্য একটি বর্ধন:

extension Array {

    func item(at index: Int) -> Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

সূচকগুলিতে সূচক রয়েছে কিনা তা পরীক্ষা করার জন্য আপনার সমতুল্য অ্যারে উপাদানগুলিকে সীমাবদ্ধ করতে হবে না।
লিও ডাবাস

হ্যাঁ - ভাল পয়েন্ট - এটি কেবল মুছুনবজেক্ট ইত্যাদির মতো অতিরিক্ত নিরাপদ পদ্ধতির জন্য প্রয়োজন হবে
মাতজন

5

আমি নিরাপদ অ্যারে পাওয়া, সেট, সন্নিবেশ করানো, খুব দরকারী খুঁজে পেয়েছি। আমি লগ এবং ত্রুটিগুলি উপেক্ষা করতে পছন্দ করি কারণ শীঘ্রই অন্য সমস্ত পরিচালনা করা শক্ত হয়ে যায়। সম্পূর্ণ কোড বেলো

/**
 Safe array get, set, insert and delete.
 All action that would cause an error are ignored.
 */
extension Array {

    /**
     Removes element at index.
     Action that would cause an error are ignored.
     */
    mutating func remove(safeAt index: Index) {
        guard index >= 0 && index < count else {
            print("Index out of bounds while deleting item at index \(index) in \(self). This action is ignored.")
            return
        }

        remove(at: index)
    }

    /**
     Inserts element at index.
     Action that would cause an error are ignored.
     */
    mutating func insert(_ element: Element, safeAt index: Index) {
        guard index >= 0 && index <= count else {
            print("Index out of bounds while inserting item at index \(index) in \(self). This action is ignored")
            return
        }

        insert(element, at: index)
    }

    /**
     Safe get set subscript.
     Action that would cause an error are ignored.
     */
    subscript (safe index: Index) -> Element? {
        get {
            return indices.contains(index) ? self[index] : nil
        }
        set {
            remove(safeAt: index)

            if let element = newValue {
                insert(element, safeAt: index)
            }
        }
    }
}

টেস্ট

import XCTest

class SafeArrayTest: XCTestCase {
    func testRemove_Successful() {
        var array = [1, 2, 3]

        array.remove(safeAt: 1)

        XCTAssert(array == [1, 3])
    }

    func testRemove_Failure() {
        var array = [1, 2, 3]

        array.remove(safeAt: 3)

        XCTAssert(array == [1, 2, 3])
    }

    func testInsert_Successful() {
        var array = [1, 2, 3]

        array.insert(4, safeAt: 1)

        XCTAssert(array == [1, 4, 2, 3])
    }

    func testInsert_Successful_AtEnd() {
        var array = [1, 2, 3]

        array.insert(4, safeAt: 3)

        XCTAssert(array == [1, 2, 3, 4])
    }

    func testInsert_Failure() {
        var array = [1, 2, 3]

        array.insert(4, safeAt: 5)

        XCTAssert(array == [1, 2, 3])
    }

    func testGet_Successful() {
        var array = [1, 2, 3]

        let element = array[safe: 1]

        XCTAssert(element == 2)
    }

    func testGet_Failure() {
        var array = [1, 2, 3]

        let element = array[safe: 4]

        XCTAssert(element == nil)
    }

    func testSet_Successful() {
        var array = [1, 2, 3]

        array[safe: 1] = 4

        XCTAssert(array == [1, 4, 3])
    }

    func testSet_Successful_AtEnd() {
        var array = [1, 2, 3]

        array[safe: 3] = 4

        XCTAssert(array == [1, 2, 3, 4])
    }

    func testSet_Failure() {
        var array = [1, 2, 3]

        array[safe: 4] = 4

        XCTAssert(array == [1, 2, 3])
    }
}

3
extension Array {
  subscript (safe index: UInt) -> Element? {
    return Int(index) < count ? self[Int(index)] : nil
  }
}

উপরে উল্লিখিত এক্সটেনশন রিটার্ন শূন্য ব্যবহার করে যদি কোনও সময় সূচি সীমা ছাড়িয়ে যায়।

let fruits = ["apple","banana"]
print("result-\(fruits[safe : 2])")

ফলাফল - শূন্য


3

আমি বুঝতে পারি এটি একটি পুরানো প্রশ্ন is আমি এই মুহুর্তে সুইফট 5.1 ব্যবহার করছি, ওপিটি সুইফট 1 বা 2 এর জন্য ছিল?

আমার আজকের মতো এই জাতীয় কিছু দরকার ছিল, তবে আমি কেবলমাত্র এক জায়গার জন্য একটি পূর্ণ স্কেল এক্সটেনশন যুক্ত করতে চাইনি এবং আরও কিছু কার্যকর (আরও থ্রেড নিরাপদ?) চেয়েছিলাম wanted আমার নেতিবাচক সূচকগুলি থেকে রক্ষা করারও দরকার ছিল না, কেবলমাত্র এগুলি শেষ হওয়ার পরে চলে যেতে পারে:

let fruit = ["Apple", "Banana", "Coconut"]

let a = fruit.dropFirst(2).first // -> "Coconut"
let b = fruit.dropFirst(0).first // -> "Apple"
let c = fruit.dropFirst(10).first // -> nil

নীলদের সাথে সিকোয়েন্সগুলি নিয়ে বিতর্ককারীদের জন্য, আপনি যে সমস্ত সম্পত্তি firstএবং lastখালি সংগ্রহের জন্য শূণ্য ফিরে আসেন সেগুলি সম্পর্কে আপনি কী করবেন ?

আমি এটি পছন্দ করেছি কারণ আমি কেবল বিদ্যমান স্টাফগুলিতে দখল করতে পারি এবং আমার পছন্দসই ফলাফল পেতে এটি ব্যবহার করতে পারি। আমি আরও জানি যে ড্রপ ফার্স্ট (এন) পুরো সংগ্রহের অনুলিপি নয়, কেবল একটি টুকরো। এবং তারপরে ইতিমধ্যে বিদ্যমান বিদ্যমান আচরণটি আমার জন্য গ্রহণ করে।


1

আমি মনে করি এটি একটি ভাল ধারণা নয়। সলিড কোড তৈরি করা ভাল বলে মনে হয় যার ফলস্বরূপ সীমার বাইরে থাকা সূচিগুলি প্রয়োগ করার চেষ্টা করা হয় না।

দয়া করে বিবেচনা করুন যে এ জাতীয় ত্রুটি থাকাটি নিঃশব্দে ব্যর্থ হয়েছে (উপরে আপনার কোড দ্বারা প্রস্তাবিত হিসাবে) ফিরে nilযাওয়ার মাধ্যমে আরও জটিল, আরও জটিলতর ত্রুটি তৈরির প্রবণ।

আপনি নিজের অনুরূপ ফ্যাশনে আপনার ওভাররাইডটি করতে পারেন এবং সাবস্ক্রিপ্টগুলি নিজের উপায়ে লিখতে পারেন। কেবল ত্রুটিটি হ'ল বিদ্যমান কোডটি উপযুক্ত নয়। আমি মনে করি জেনেরিক এক্সকে ওভাররাইড করার জন্য একটি হুক খুঁজে বের করতে হবে [i] (সি হিসাবে কোনও পাঠ্য প্রিপ্রোসেসর ছাড়াইও) চ্যালেঞ্জ হবে।

আমি সবচেয়ে কাছের এটি ভাবতে পারি

// compile error:
if theIndex < str.count && let existing = str[theIndex]

সম্পাদনা : এটি আসলে কাজ করে। এক রৈখিক!!

func ifInBounds(array: [AnyObject], idx: Int) -> AnyObject? {
    return idx < array.count ? array[idx] : nil
}

if let x: AnyObject = ifInBounds(swiftarray, 3) {
    println(x)
}
else {
    println("Out of bounds")
}

6
আমি দ্বিমত পোষণ করব - alচ্ছিক বাঁধাইয়ের বিষয়টি হ'ল শর্তটি পূরণ হলেই এটি সফল হয়। (Optionচ্ছিকের জন্য, এর অর্থ একটি মান রয়েছে)) if letএই ক্ষেত্রে একটি ব্যবহার করা প্রোগ্রামটিকে আরও জটিল করে তোলে না, ত্রুটিগুলি আরও জটিল করে তোলে না। এটি কেবলমাত্র ifএক-রেখাযুক্ত, ঘনীভূত বিবৃতিতে twoতিহ্যবাহী দ্বি-বিবৃতি সীমা চেক এবং প্রকৃত অনুসন্ধানকে ঘনীভূত করে। সেখানে মামলা (বিশেষত একটি UI 'তে কর্মরত) যেখানে এটা স্বাভাবিক একটি সূচক সীমার বাইরে হতে, একটি জিজ্ঞাসা মত NSTableViewজন্য selectedRowএকটি নির্বাচন ছাড়াই।
ক্রেগ ওটিস

3
@ মুন্ডি এটি ওপি-র প্রশ্নের উত্তরের চেয়ে একটি মন্তব্য বলে মনে হচ্ছে।
jlehr

1
@ ক্রেইগঅ্যাটিস নিশ্চিত নই যে আমি সম্মত। আপনি এই চেকটি একটি "একক রেখায়, ঘনীভূত বিবৃতিতে" সংক্ষেপে লিখতে পারেন , যেমন countElementsওপি যেমন ব্যবহার করেছেন বা যেমন করেছেন count, ঠিক তেমনভাবে নয় যেমন ভাষা অ্যারে সাবস্ক্রিপগুলি লেখার সংজ্ঞা দেয়।
মুন্ডি

1
পছন্দ করেছেন কোনও সমস্যার উদ্ভবের উদ্দেশ্য বা প্রজ্ঞাটি নিয়ে প্রশ্ন উত্থাপন করা মোটামুটি খেলা।
মুন্ডি

2
@ মুন্ডি হে, বিশেষত যদি আপনি পরে এটিকে সম্পাদনা করেন তবে সত্যিকার অর্থে প্রশ্নের উত্তর দিন। :-)
jlehr

1

আমি nilআমার ব্যবহারের ক্ষেত্রে অ্যারের সাথে প্যাড করেছি:

let components = [1, 2]
var nilComponents = components.map { $0 as Int? }
nilComponents += [nil, nil, nil]

switch (nilComponents[0], nilComponents[1], nilComponents[2]) {
case (_, _, .Some(5)):
    // process last component with 5
default:
    break
}

এছাড়াও safe:এরিকা সাদুন / মাইক অ্যাশ-এর ​​লেবেল সহ সাবস্ক্রিপ্ট এক্সটেনশানটি দেখুন : http://ericasadun.com/2015/06/01/swift-safe-array-indexing-my-Liveite-thing-of-the-new-week/


0

সুইফ্ট তালিকার জন্য "সাধারণভাবে প্রত্যাখ্যাত পরিবর্তনগুলি" ক্র্যাশ না করে বিকল্প হিসাবে ফিরতে অ্যারে সাবস্ক্রিপ্ট অ্যাক্সেস পরিবর্তন করার উল্লেখ রয়েছে :

করুন Array<T>সাবস্ক্রিপ্ট এক্সেস রিটার্ন T?বা T!পরিবর্তে T: বর্তমান অ্যারের আচরণ ইচ্ছাকৃত , যেমন নির্ভুলভাবে সত্য যে আউট-অফ-সীমা অ্যারে অ্যাক্সেস যুক্তিবিজ্ঞান ত্রুটি প্রতিফলিত করে। বর্তমানের আচরণটি পরিবর্তন Arrayঅ্যাক্সেসগুলিকে অগ্রহণযোগ্য ডিগ্রীতে ধীর করবে । এই বিষয়টি এর আগেও একাধিকবার উঠে এসেছিল তবে এটি গ্রহণযোগ্য হওয়ার সম্ভাবনা খুব কম।

https://github.com/apple/swift-evolution/blob/master/commonly_proposed.md#strings-characters-and-collection-types

সুতরাং মৌলিক সাবস্ক্রিপ্ট অ্যাক্সেস একটি returnচ্ছিক ফিরে আসতে পরিবর্তন হবে না।

তবে সুইফট টিম / সম্প্রদায়টি কোনও ফাংশন বা সাবস্ক্রিপ্টের মাধ্যমে অ্যারেগুলিতে নতুন optionচ্ছিক-রিটার্নিং অ্যাক্সেস প্যাটার্ন যুক্ত করতে খোলা মনে হচ্ছে ।

এটি সুইফট বিবর্তন ফোরামে এখানে প্রস্তাবিত এবং আলোচনা করা হয়েছে:

https://forums.swift.org/t/add-accessor-with-bounds-check-to-array/16871

উল্লেখযোগ্যভাবে, ক্রিস ল্যাটনার এই ধারণাকে একটি "+1" দিয়েছেন:

সম্মত, এর জন্য প্রায়শই প্রস্তাবিত বানানটি: yourArray[safe: idx]যা আমার কাছে দুর্দান্ত বলে মনে হয়। এটি যুক্ত করার জন্য আমি খুব +1।

https://forums.swift.org/t/add-accessor-with-bounds-check-to-array/16871/13

তাই এটি সুইফটের ভবিষ্যতের কিছু সংস্করণে বাক্সের বাইরে থাকা সম্ভব। আমি চাইলে যে কেউ এই সুইফট বিবর্তনের থ্রেডে অবদান রাখতে চায় তাকে উত্সাহিত করব।


0

অপারেশন কেন ব্যর্থ হয় তা প্রচার করতে, ত্রুটিগুলি বিকল্পগুলির চেয়ে ভাল। সাবস্ক্রিপ্টগুলি ত্রুটি ফেলে দিতে পারে না, সুতরাং এটি একটি পদ্ধতি হয়ে উঠেছে।

public extension Collection {
  /// - Returns: same as subscript, if index is in bounds
  /// - Throws: CollectionIndexingError
  func element(at index: Index) throws -> Element {
    guard indices.contains(index)
    else { throw CollectionIndexingError() }

    return self[index]
  }
}

/// Thrown when `element(at:)` is called with an invalid index.
public struct CollectionIndexingError: Error { }
XCTAssertThrowsError( try ["🐾", "🥝"].element(at: 2) )

let optionals = [1, 2, nil]
XCTAssertEqual(try optionals.element(at: 0), 1)

XCTAssertThrowsError( try optionals.element(at: optionals.endIndex) )
{ XCTAssert($0 is CollectionIndexingError) }

0

নিশ্চিত না কেন কেন কেউ, একটি এক্সটেনশন রেখেছিল যাতে স্বয়ংক্রিয়ভাবে অ্যারে বাড়ানোর জন্য সেটারও রয়েছে

extension Array where Element: ExpressibleByNilLiteral {
    public subscript(safe index: Int) -> Element? {
        get {
            guard index >= 0, index < endIndex else {
                return nil
            }

            return self[index]
        }

        set(newValue) {
            if index >= endIndex {
                self.append(contentsOf: Array(repeating: nil, count: index - endIndex + 1))
            }

            self[index] = newValue ?? nil
        }
    }
}

ব্যবহার সহজ এবং সুইফট 5.1 হিসাবে কাজ করে

var arr:[String?] = ["A","B","C"]

print(arr) // Output: [Optional("A"), Optional("B"), Optional("C")]

arr[safe:10] = "Z"

print(arr) // [Optional("A"), Optional("B"), Optional("C"), nil, nil, nil, nil, nil, nil, nil, Optional("Z")]

দ্রষ্টব্য: দ্রুতগতিতে অ্যারে বাড়ানোর সময় আপনার পারফরম্যান্সের ব্যয় (সময় / স্থান উভয়ই) বুঝতে হবে - তবে ছোট সমস্যাগুলির জন্য মাঝে মাঝে আপনার নিজের পায়ে সুইফিং বন্ধ করার জন্য সুইফ্টের দরকার হয়


-1

অ্যারের জন্য আমি একটি সাধারণ এক্সটেনশন করেছি

extension Array where Iterator.Element : AnyObject {
    func iof (_ i : Int ) -> Iterator.Element? {
        if self.count > i {
            return self[i] as Iterator.Element
        }
        else {
            return nil
        }
    }

}

এটি নকশা হিসাবে নিখুঁতভাবে কাজ করে

উদাহরণ

   if let firstElemntToLoad = roots.iof(0)?.children?.iof(0)?.cNode, 

-1

সুইফ্ট 5 ব্যবহার

extension WKNavigationType {
    var name : String {
        get {
            let names = ["linkAct","formSubm","backForw","reload","formRelo"]
            return names.indices.contains(self.rawValue) ? names[self.rawValue] : "other"
        }
    }
}

শেষ হয়েছে তবে সত্যিই পছন্দ করতে চাই সাধারণত wanted

[<collection>][<index>] ?? <default>

তবে সংগ্রহটি প্রাসঙ্গিক হিসাবে আমার ধারণা এটি যথাযথ।


এই উত্তর গৃহীত উত্তর থেকে আলাদা কীভাবে? আমার হিসাবে, এটি দেখতে হুবহু একই (সদৃশ)।
লেগনাফটিক

-1

যখন আপনাকে কেবল অ্যারে থেকে মানগুলি পেতে হয় এবং আপনি একটি ছোট পারফরম্যান্স পেনাল্টি (যেমন আপনার সংগ্রহটি বিশাল না হয়) আপত্তি করেন না, তখন অভিধান-ভিত্তিক বিকল্প রয়েছে যা এতে জড়িত না (আমার পক্ষে খুব জেনেরিক) স্বাদ) সংগ্রহ এক্সটেনশন:

// Assuming you have a collection named array:
let safeArray = Dictionary(uniqueKeysWithValues: zip(0..., array))
let value = safeArray[index] ?? defaultValue;
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.