সুইফট - একাধিক মাপদণ্ডের সাথে অবজেক্টগুলির অ্যারে বাছাই করুন


92

আমার কাছে Contactবস্তুর একটি অ্যারে রয়েছে :

var contacts:[Contact] = [Contact]()

যোগাযোগ শ্রেণি:

Class Contact:NSOBject {
    var firstName:String!
    var lastName:String!
}

এবং আমি এই অ্যারেটি বাছাই করতে চাই lastNameএবং তারপরে firstNameযদি কিছু পরিচিতি একই রকম হয় lastName

আমি এই মানদণ্ডগুলির মধ্যে একটি অনুসারে বাছাই করতে সক্ষম, তবে উভয়ই নয়।

contacts.sortInPlace({$0.lastName < $1.lastName})

এই অ্যারেটি বাছাই করতে আমি কীভাবে আরও মানদণ্ড যুক্ত করতে পারি?


4
আপনি ঠিক বলেছেন ঠিক একইভাবে এটি করুন! আপনার কোঁকড়া ধনুর্বন্ধনীগুলির ভিতরে কোডটি বলতে হবে: "যদি শেষ নামগুলি একই হয় তবে প্রথম নাম অনুসারে বাছাই করুন; অন্যথায় শেষ নাম অনুসারে বাছাই করুন"।
ম্যাট

4
আমি এখানে কয়েকটি কোডের গন্ধ দেখতে পাচ্ছি: 1) Contactসম্ভবত উত্তরাধিকার সূত্রে প্রাপ্ত হওয়া উচিত নয় NSObject, 2) Contactসম্ভবত স্ট্রাক্ট এবং 3) হওয়া উচিত firstNameএবং lastNameসম্ভবত স্পষ্টতই মোড়ানো বিকল্পগুলি হওয়া উচিত নয়।
আলেকজান্ডার - মনিকা পুনরায় স্থাপন করুন

4
@ এমমচিলভ যোগাযোগের কাঠামো হওয়ার পরামর্শ দেওয়ার কোনও কারণ নেই কারণ আপনি জানেন না যে তার বাকী কোডটি ইতিমধ্যে এটির উদাহরণ ব্যবহার করার ক্ষেত্রে রেফারেন্স শব্দার্থের উপর নির্ভর করে কিনা you
প্যাট্রিক গোলে

4
@ এমমচিলভ "সম্ভবত" বিভ্রান্ত করছে কারণ আপনি বাকি কোডবেস সম্পর্কে ঠিক কিছু জানেন না। যদি এটি কোনও স্ট্রাক্টে পরিবর্তন করা হয়, হস্তক্ষেপে উদাহরণটি পরিবর্তনের পরিবর্তে ভারগুলি পরিবর্তনের সময় হঠাৎ সমস্ত অনুলিপি তৈরি হয়। এটি আচরণের ক্ষেত্রে কঠোর পরিবর্তন এবং এর ফলে বাগগুলি সম্ভবত "সম্ভবত" হয়ে থাকে কারণ রেফারেন্স এবং মান শব্দার্থক উভয়ের জন্যই এটি যথাযথভাবে কোড করা সম্ভব নয় ।
প্যাট্রিক গোলে

4
@ এমমচিলভ এখনও সম্ভবত এটি কাঠামো হওয়ার কারণ সম্পর্কে একটি কারণ শুনতে পারেন নি। আমি মনে করি না যে ওপির তার পরামর্শগুলির প্রশংসার প্রশংসা করবে যা তার প্রোগ্রামের বাকী অংশগুলির শব্দার্থবিজ্ঞানকে সংশোধন করবে, বিশেষত যখন হাতে সমস্যা সমাধানের প্রয়োজন ছিল না তখন। সংকলনের নিয়মগুলি কারও কারও কাছে আইনী ধারণা ছিল না ... হতে পারে আমি ভুল ওয়েবসাইটে আছি
প্যাট্রিক গোলে

উত্তর:


120

"একাধিক মানদণ্ড অনুসারে বাছাই করা" এর অর্থ কী তা চিন্তা করুন। এর অর্থ হ'ল দুটি বস্তুকে প্রথমে একটি মানদণ্ডের সাথে তুলনা করা হয়। তারপরে, যদি সেই মানদণ্ড একই হয় তবে পরবর্তী মানদণ্ডগুলির সাথে বন্ধনগুলি ভেঙে দেওয়া হবে, এবং যতক্ষণ না আপনি পছন্দসই অর্ডার পেয়ে যান।

let sortedContacts = contacts.sort {
    if $0.lastName != $1.lastName { // first, compare by last names
        return $0.lastName < $1.lastName
    }
    /*  last names are the same, break ties by foo
    else if $0.foo != $1.foo {
        return $0.foo < $1.foo
    }
    ... repeat for all other fields in the sorting
    */
    else { // All other fields are tied, break ties by last name
        return $0.firstName < $1.firstName
    }
}

আপনি এখানে যা দেখছেন তা হ'ল Sequence.sorted(by:)পদ্ধতি , যা উপাদানগুলি কীভাবে তুলনা করে তা নির্ধারণের জন্য প্রদত্ত ক্লোজারের পরামর্শ নেয়।

যদি আপনার বাছাই অনেক জায়গায় ব্যবহৃত হয়, আপনার Comparable প্রোটোকলের সাথে আপনার ধরণটি অনুসারে তৈরি করা ভাল । এই পদ্ধতিতে, আপনি Sequence.sorted()পদ্ধতিটি ব্যবহার করতে পারেন যা উপাদানগুলির তুলনা কীভাবে তুলনা করে তা নির্ধারণ করতে Comparable.<(_:_:)অপারেটরের আপনার প্রয়োগের পরামর্শ নেয় । এই ভাবে, যদি আপনি কোন সাজাতে পারেন Sequenceএর Contactকি কখনো বাছাই কোড নকল না করেও সে।


4
elseশরীর এর মধ্যে হওয়া উচিত { ... }অন্যথায় কোড কম্পাইল করে না।
লুকা অ্যাঞ্জলেটটি

বুঝেছি. আমি এটি বাস্তবায়নের চেষ্টা করেছি কিন্তু সিনট্যাক্সটি সঠিকভাবে পেলাম না। অনেক ধন্যবাদ.
sbkl

জন্য sortবনাম sortInPlaceদেখতে এখানে । Aslo দেখতে এই নিচে, এটা আরো অনেক কিছু মডুলার এর
মধু

sortInPlaceআপনি ব্যবহার করতে হবে পরিবর্তে, সুইফট 3 এ আর উপলব্ধ নেই sort()sort()অ্যারে নিজেই পরিবর্তন করতে হবে। এছাড়াও একটি নতুন ফানকের নাম রয়েছে sorted()যা একটি সাজানো অ্যারে ফিরিয়ে দেবে
হানি

4
@ অ্যাথানাসিয়াসঅফএলেক্স ব্যবহার ==করা ভাল ধারণা নয়। এটি কেবল 2 টি বৈশিষ্ট্যের জন্য কাজ করে। এর চেয়ে বড় কিছু না, এবং আপনি নিজেকে প্রচুর পরিমাণে বুলিয়ান এক্সপ্রেশন দিয়ে পুনরাবৃত্তি করতে শুরু করেন
আলেকজান্ডার - মনিকা

123

একাধিক মানদণ্ডের তুলনা করতে টিপলস ব্যবহার করা

(এবং যদি সমতুল্য, তারপর অন্য তুলনার অর্থাত শ্রেণীবিভাজন এক তুলনার,) কেমন একাধিক মানদণ্ডের দ্বারা করণ সত্যিই সহজ উপায় ব্যবহার করা tuples , যেমন <এবং >অপারেটরদের তাদের জন্য overloads যে lexicographic তুলনা সঞ্চালন আছে।

/// Returns a Boolean value indicating whether the first tuple is ordered
/// before the second in a lexicographical ordering.
///
/// Given two tuples `(a1, a2, ..., aN)` and `(b1, b2, ..., bN)`, the first
/// tuple is before the second tuple if and only if
/// `a1 < b1` or (`a1 == b1` and
/// `(a2, ..., aN) < (b2, ..., bN)`).
public func < <A : Comparable, B : Comparable>(lhs: (A, B), rhs: (A, B)) -> Bool

উদাহরণ স্বরূপ:

struct Contact {
  var firstName: String
  var lastName: String
}

var contacts = [
  Contact(firstName: "Leonard", lastName: "Charleson"),
  Contact(firstName: "Michael", lastName: "Webb"),
  Contact(firstName: "Charles", lastName: "Alexson"),
  Contact(firstName: "Michael", lastName: "Elexson"),
  Contact(firstName: "Alex", lastName: "Elexson"),
]

contacts.sort {
  ($0.lastName, $0.firstName) <
    ($1.lastName, $1.firstName)
}

print(contacts)

// [
//   Contact(firstName: "Charles", lastName: "Alexson"),
//   Contact(firstName: "Leonard", lastName: "Charleson"),
//   Contact(firstName: "Alex", lastName: "Elexson"),
//   Contact(firstName: "Michael", lastName: "Elexson"),
//   Contact(firstName: "Michael", lastName: "Webb")
// ]

এটি lastNameপ্রথমে উপাদানগুলির বৈশিষ্ট্যগুলির তুলনা করবে । যদি তারা সমান না হয়, তবে বাছাই <ক্রমটি তাদের সাথে তুলনার ভিত্তিতে হবে । তারা যদি হয় সমান, তাহলে এটি tuple উপাদানের পরবর্তী যুগল সম্মুখের সরানো, তুলনা অর্থাৎ করবে firstNameবৈশিষ্ট্য।

মান লাইব্রেরি উপলব্ধ <এবং >2 6 উপাদানের tuples জন্য overloads।

আপনি যদি বিভিন্ন বৈশিষ্ট্যের জন্য আলাদা বাছাইয়ের আদেশ চান তবে আপনি কেবলমাত্র টিপলগুলিতে উপাদানগুলি অদলবদল করতে পারেন:

contacts.sort {
  ($1.lastName, $0.firstName) <
    ($0.lastName, $1.firstName)
}

// [
//   Contact(firstName: "Michael", lastName: "Webb")
//   Contact(firstName: "Alex", lastName: "Elexson"),
//   Contact(firstName: "Michael", lastName: "Elexson"),
//   Contact(firstName: "Leonard", lastName: "Charleson"),
//   Contact(firstName: "Charles", lastName: "Alexson"),
// ]

এটি এখন lastNameঅবতরণ করে সাজানো হবে, তারপরে firstNameআরোহণ।


sort(by:)একাধিক পূর্বাভাস নেয় এমন ওভারলোডের সংজ্ঞা দেওয়া হচ্ছে

ক্লোজার এবং সোর্টডিসিপেক্টরগুলির সাথে সংগ্রহগুলি mapবাছাইয়ের আলোচনায় অনুপ্রাণিত হয়ে আরেকটি বিকল্প হ'ল একটি কাস্টম ওভারলোডের সংজ্ঞা দেওয়া sort(by:)এবং sorted(by:)এটি একাধিক ভবিষ্যদ্বাণীগুলির সাথে ডিল করে - যেখানে প্রতিটি ভবিষ্যদ্বাণীকে উপাদানগুলির ক্রম সিদ্ধান্ত নেওয়ার পরিবর্তে বিবেচনা করা হয়।

extension MutableCollection where Self : RandomAccessCollection {
  mutating func sort(
    by firstPredicate: (Element, Element) -> Bool,
    _ secondPredicate: (Element, Element) -> Bool,
    _ otherPredicates: ((Element, Element) -> Bool)...
  ) {
    sort(by:) { lhs, rhs in
      if firstPredicate(lhs, rhs) { return true }
      if firstPredicate(rhs, lhs) { return false }
      if secondPredicate(lhs, rhs) { return true }
      if secondPredicate(rhs, lhs) { return false }
      for predicate in otherPredicates {
        if predicate(lhs, rhs) { return true }
        if predicate(rhs, lhs) { return false }
      }
      return false
    }
  }
}

extension Sequence {
  mutating func sorted(
    by firstPredicate: (Element, Element) -> Bool,
    _ secondPredicate: (Element, Element) -> Bool,
    _ otherPredicates: ((Element, Element) -> Bool)...
  ) -> [Element] {
    return sorted(by:) { lhs, rhs in
      if firstPredicate(lhs, rhs) { return true }
      if firstPredicate(rhs, lhs) { return false }
      if secondPredicate(lhs, rhs) { return true }
      if secondPredicate(rhs, lhs) { return false }
      for predicate in otherPredicates {
        if predicate(lhs, rhs) { return true }
        if predicate(rhs, lhs) { return false }
      }
      return false
    }
  }
}

( secondPredicate:প্যারামিটারটি দুর্ভাগ্যজনক, তবে বিদ্যমান sort(by:)ওভারলোডের সাথে অস্পষ্টতা তৈরি এড়াতে প্রয়োজনীয় )

এটি তখন আমাদের বলতে দেয় ( contactsআগের থেকে অ্যারে ব্যবহার করে ):

contacts.sort(by:
  { $0.lastName > $1.lastName },  // first sort by lastName descending
  { $0.firstName < $1.firstName } // ... then firstName ascending
  // ...
)

print(contacts)

// [
//   Contact(firstName: "Michael", lastName: "Webb")
//   Contact(firstName: "Alex", lastName: "Elexson"),
//   Contact(firstName: "Michael", lastName: "Elexson"),
//   Contact(firstName: "Leonard", lastName: "Charleson"),
//   Contact(firstName: "Charles", lastName: "Alexson"),
// ]

// or with sorted(by:)...
let sortedContacts = contacts.sorted(by:
  { $0.lastName > $1.lastName },  // first sort by lastName descending
  { $0.firstName < $1.firstName } // ... then firstName ascending
  // ...
)

যদিও কল-সাইট টিউপল বৈকল্পিকের মতো সংক্ষিপ্ত নয়, আপনি কী তুলনা করছেন এবং কোন ক্রমে অতিরিক্ত স্পষ্টতা অর্জন করেছেন।


অনুসারে Comparable

আপনি যদি নিয়মিত এই ধরণের তুলনা নিয়মিত করে যাচ্ছেন তবে @ এমমচিলভ এবং @ অ্যাপজিউয়ারলাইফের পরামর্শ অনুসারে, আপনি এটি মেনে চলতে Contactপারেন Comparable:

extension Contact : Comparable {
  static func == (lhs: Contact, rhs: Contact) -> Bool {
    return (lhs.firstName, lhs.lastName) ==
             (rhs.firstName, rhs.lastName)
  }

  static func < (lhs: Contact, rhs: Contact) -> Bool {
    return (lhs.lastName, lhs.firstName) <
             (rhs.lastName, rhs.firstName)
  }
}

এবং এখন কেবল sort()একটি আরোহণের আদেশের জন্য কল করুন :

contacts.sort()

বা sort(by: >)একটি উতরাই অর্ডার জন্য:

contacts.sort(by: >)

নেস্টেড প্রকারে কাস্টম সাজানোর অর্ডারগুলি সংজ্ঞায়িত করা হচ্ছে

আপনি যদি চান এমন অন্য ধরণের অর্ডারগুলি ব্যবহার করতে চান তবে আপনি সেগুলি নেস্টেড টাইপের মধ্যে সংজ্ঞায়িত করতে পারেন:

extension Contact {
  enum Comparison {
    static let firstLastAscending: (Contact, Contact) -> Bool = {
      return ($0.firstName, $0.lastName) <
               ($1.firstName, $1.lastName)
    }
  }
}

এবং তারপরে কেবল এটিকে কল করুন:

contacts.sort(by: Contact.Comparison.firstLastAscending)

contacts.sort { ($0.lastName, $0.firstName) < ($1.lastName, $1.firstName) } সাহায্য করেছে ধন্যবাদ
প্রভাকর কাশী

আমার মত বৈশিষ্ট্য অনুসারে বাছাই করা হবে optionals হন, তাহলে আপনি এই ভালো কিছু করতে পারে: contacts.sort { ($0.lastName ?? "", $0.firstName ?? "") < ($1.lastName ?? "", $1.firstName ?? "") }
ববকউ

হোলি মলি! এত সহজ তবুও এত দক্ষ ... কেন আমি এর আগে কখনও শুনিনি ?! অনেক ধন্যবাদ!
এথিনাইল

@ BobCowe ""আপনাকে অন্যান্য স্ট্রিংয়ের সাথে কীভাবে তুলনা করে (এটি খালি খালি স্ট্রিংয়ের আগে আসে) এর দয়াতে আপনাকে ছেড়ে যায় । আপনি যদি nilপরিবর্তে তালিকার শেষে আসতে চান তবে এটি একধরনের অন্তর্নিহিত, কিণ্ডা যাদু এবং জটিল নয় inf আমি আপনাকে আমার nilComparatorফাংশন স্ট্যাকওভারফ্লো.com
আলেকজান্ডার -

19

2 টি মাপদণ্ডে বাছাইয়ের জন্য আরও একটি সহজ পদ্ধতির নীচে দেখানো হয়েছে।

প্রথম ক্ষেত্রের জন্য পরীক্ষা করুন, এক্ষেত্রে এটি হ'ল lastNameযদি তারা সমান অনুসারে না হয় lastName, যদি lastNameএর সমান হয় তবে এই ক্ষেত্রে দ্বিতীয় ক্ষেত্র অনুসারে বাছাই করুন firstName

contacts.sort { $0.lastName == $1.lastName ? $0.firstName < $1.firstName : $0.lastName < $1.lastName  }

এটি টিপলসের চেয়ে আরও নমনীয়তা দেয়।
বাবাক

5

কথাসাহিতিক ধরণের জিনিসটি যা হ্যামিশের বর্ণনা অনুসারে করতে পারে না তা হ'ল বিভিন্ন বাছাইয়ের দিকনির্দেশনা পরিচালনা করা, প্রথম ক্ষেত্রের উতরাই অনুসারে বাছাই করুন, পরবর্তী ক্ষেত্রের আরোহণ ইত্যাদি etc.

আমি কীভাবে এটি সুইফট 3 এ ব্লগ পোস্ট তৈরি করেছি এবং কোডটি সহজ এবং পঠনযোগ্য রাখি।

আপনি এখানে পেতে পারেন:

http://master-method.com/index.php/2016/11/23/sort-a-sequence-ie-arrays-of-objects-by-m Multipleple-properties-in-swift-3/

আপনি এখানে কোড সহ একটি গিটহাবের সংগ্রহস্থল খুঁজে পেতে পারেন:

https://github.com/jallauca/SortByM মাল্টিপলফিল্ডস সুইফট.প্লেগ্রাউন্ড

এগুলির সমস্ত বক্তব্য, বলুন, আপনার কাছে অবস্থানের তালিকা থাকলে আপনি এটি করতে সক্ষম হবেন:

struct Location {
    var city: String
    var county: String
    var state: String
}

var locations: [Location] {
    return [
        Location(city: "Dania Beach", county: "Broward", state: "Florida"),
        Location(city: "Fort Lauderdale", county: "Broward", state: "Florida"),
        Location(city: "Hallandale Beach", county: "Broward", state: "Florida"),
        Location(city: "Delray Beach", county: "Palm Beach", state: "Florida"),
        Location(city: "West Palm Beach", county: "Palm Beach", state: "Florida"),
        Location(city: "Savannah", county: "Chatham", state: "Georgia"),
        Location(city: "Richmond Hill", county: "Bryan", state: "Georgia"),
        Location(city: "St. Marys", county: "Camden", state: "Georgia"),
        Location(city: "Kingsland", county: "Camden", state: "Georgia"),
    ]
}

let sortedLocations =
    locations
        .sorted(by:
            ComparisonResult.flip <<< Location.stateCompare,
            Location.countyCompare,
            Location.cityCompare
        )

4
"কথাসাহিতিক ধরণের জিনিসগুলি যা হ্যামিগের বর্ণনা অনুসারে করতে পারে না তা হ'ল বিভিন্ন বাছাই করার দিকনির্দেশনা পরিচালনা করা" - হ্যাঁ তারা কেবলমাত্র টিপলগুলিতে উপাদানগুলিকে অদলবদল করতে পারে;)
হামিশ

আমি এটি একটি আকর্ষণীয় তাত্ত্বিক অনুশীলন পাই তবে @ হামিশের উত্তরের চেয়ে অনেক জটিল much কম কোড আমার মতে ভাল কোড।
ম্যানুয়েল

5

এই প্রশ্নের ইতিমধ্যে অনেক দুর্দান্ত উত্তর রয়েছে, তবে আমি একটি নিবন্ধের দিকে নির্দেশ করতে চাই - সুইফটে ইন ডিসক্রিপ্টরগুলি সাজান । আমাদের একাধিক মানদণ্ড বাছাই করার বিভিন্ন উপায় রয়েছে।

  1. এনএসএসর্টডেস্কিটার ব্যবহার করে, এই পদ্ধতিতে কিছু সীমাবদ্ধতা রয়েছে, অবজেক্টটি একটি শ্রেণি হওয়া উচিত এবং এনএসবজেক্ট থেকে উত্তরাধিকার সূত্রে প্রাপ্ত।

    class Person: NSObject {
        var first: String
        var last: String
        var yearOfBirth: Int
        init(first: String, last: String, yearOfBirth: Int) {
            self.first = first
            self.last = last
            self.yearOfBirth = yearOfBirth
        }
    
        override var description: String {
            get {
                return "\(self.last) \(self.first) (\(self.yearOfBirth))"
            }
        }
    }
    
    let people = [
        Person(first: "Jo", last: "Smith", yearOfBirth: 1970),
        Person(first: "Joe", last: "Smith", yearOfBirth: 1970),
        Person(first: "Joe", last: "Smyth", yearOfBirth: 1970),
        Person(first: "Joanne", last: "smith", yearOfBirth: 1985),
        Person(first: "Joanne", last: "smith", yearOfBirth: 1970),
        Person(first: "Robert", last: "Jones", yearOfBirth: 1970),
    ]
    

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

    let lastDescriptor = NSSortDescriptor(key: "last", ascending: true,
      selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
    let firstDescriptor = NSSortDescriptor(key: "first", ascending: true, 
      selector: #selector(NSString.localizedCaseInsensitiveCompare(_:)))
    let yearDescriptor = NSSortDescriptor(key: "yearOfBirth", ascending: true)
    
    
    
    (people as NSArray).sortedArray(using: [lastDescriptor, firstDescriptor, yearDescriptor]) 
    // [Robert Jones (1970), Jo Smith (1970), Joanne smith (1970), Joanne smith (1985), Joe Smith (1970), Joe Smyth (1970)]
    
  2. শেষ নাম / প্রথম নামের সাথে বাছাইয়ের সুইফ্ট পদ্ধতি ব্যবহার করে। এই পদ্ধতিতে উভয় শ্রেণি / কাঠামোর সাথে কাজ করা উচিত। যাইহোক, আমরা এখানে বছর জন্মের পরে বাছাই না।

    let sortedPeople = people.sorted { p0, p1 in
        let left =  [p0.last, p0.first]
        let right = [p1.last, p1.first]
    
        return left.lexicographicallyPrecedes(right) {
            $0.localizedCaseInsensitiveCompare($1) == .orderedAscending
        }
    }
    sortedPeople // [Robert Jones (1970), Jo Smith (1970), Joanne smith (1985), Joanne smith (1970), Joe Smith (1970), Joe Smyth (1970)]
    
  3. এনএসএসর্টডেস্কিটার প্রেরণের দ্রুত উপায়। এটি এমন ধারণাটি ব্যবহার করে যে 'ফাংশনগুলি প্রথম শ্রেণীর ধরণের'। SortDescriptor একটি ফাংশন প্রকার, দুটি মান নেয়, একটি বিল দেয়। সাজ্টবাই ফার্স্টনাম বলুন আমরা দুটি পরামিতি ($ 0, $ 1) নিই এবং তাদের প্রথম নামগুলি তুলনা করি। কম্বিনে ফাংশনগুলি সার্টডেস্ক্রিপ্টরগুলির একগুচ্ছ লাগে, তাদের সকলের সাথে তুলনা করে অর্ডার দেয়।

    typealias SortDescriptor<Value> = (Value, Value) -> Bool
    
    let sortByFirstName: SortDescriptor<Person> = {
        $0.first.localizedCaseInsensitiveCompare($1.first) == .orderedAscending
    }
    let sortByYear: SortDescriptor<Person> = { $0.yearOfBirth < $1.yearOfBirth }
    let sortByLastName: SortDescriptor<Person> = {
        $0.last.localizedCaseInsensitiveCompare($1.last) == .orderedAscending
    }
    
    func combine<Value>
        (sortDescriptors: [SortDescriptor<Value>]) -> SortDescriptor<Value> {
        return { lhs, rhs in
            for isOrderedBefore in sortDescriptors {
                if isOrderedBefore(lhs,rhs) { return true }
                if isOrderedBefore(rhs,lhs) { return false }
            }
            return false
        }
    }
    
    let combined: SortDescriptor<Person> = combine(
        sortDescriptors: [sortByLastName,sortByFirstName,sortByYear]
    )
    people.sorted(by: combined)
    // [Robert Jones (1970), Jo Smith (1970), Joanne smith (1970), Joanne smith (1985), Joe Smith (1970), Joe Smyth (1970)]
    

    এটি ভাল কারণ আপনি এটি স্ট্রাক্ট এবং ক্লাস উভয়ই দিয়ে ব্যবহার করতে পারেন, আপনি এমনকি এটি নীল সাথে তুলনা করতে প্রসারিত করতে পারেন।

তবুও, মূল নিবন্ধটি পড়ার জন্য দৃ strongly়ভাবে পরামর্শ দেওয়া হচ্ছে। এটিতে আরও অনেক বিশদ রয়েছে এবং ভালভাবে ব্যাখ্যা করা হয়েছে।


2

আমি হামিশের টিপল সলিউশনটি ব্যবহার করার পরামর্শ দিচ্ছি কারণ এটি অতিরিক্ত কোডের প্রয়োজন হয় না।


আপনি যদি এমন কিছু চান যা ifবিবৃতিগুলির মতো আচরণ করে তবে ব্রাঞ্চিংয়ের যুক্তিটিকে সহজতর করে, আপনি এই সমাধানটি ব্যবহার করতে পারেন, যা আপনাকে নিম্নলিখিতটি করার অনুমতি দেয়:

animals.sort {
  return comparisons(
    compare($0.family, $1.family, ascending: false),
    compare($0.name, $1.name))
}

এখানে ফাংশন যা আপনাকে এটি করার অনুমতি দেয়:

func compare<C: Comparable>(_ value1Closure: @autoclosure @escaping () -> C, _ value2Closure: @autoclosure @escaping () -> C, ascending: Bool = true) -> () -> ComparisonResult {
  return {
    let value1 = value1Closure()
    let value2 = value2Closure()
    if value1 == value2 {
      return .orderedSame
    } else if ascending {
      return value1 < value2 ? .orderedAscending : .orderedDescending
    } else {
      return value1 > value2 ? .orderedAscending : .orderedDescending
    }
  }
}

func comparisons(_ comparisons: (() -> ComparisonResult)...) -> Bool {
  for comparison in comparisons {
    switch comparison() {
    case .orderedSame:
      continue // go on to the next property
    case .orderedAscending:
      return true
    case .orderedDescending:
      return false
    }
  }
  return false // all of them were equal
}

আপনি যদি এটি পরীক্ষা করে দেখতে চান তবে আপনি এই অতিরিক্ত কোডটি ব্যবহার করতে পারেন:

enum Family: Int, Comparable {
  case bird
  case cat
  case dog

  var short: String {
    switch self {
    case .bird: return "B"
    case .cat: return "C"
    case .dog: return "D"
    }
  }

  public static func <(lhs: Family, rhs: Family) -> Bool {
    return lhs.rawValue < rhs.rawValue
  }
}

struct Animal: CustomDebugStringConvertible {
  let name: String
  let family: Family

  public var debugDescription: String {
    return "\(name) (\(family.short))"
  }
}

let animals = [
  Animal(name: "Leopard", family: .cat),
  Animal(name: "Wolf", family: .dog),
  Animal(name: "Tiger", family: .cat),
  Animal(name: "Eagle", family: .bird),
  Animal(name: "Cheetah", family: .cat),
  Animal(name: "Hawk", family: .bird),
  Animal(name: "Puma", family: .cat),
  Animal(name: "Dalmatian", family: .dog),
  Animal(name: "Lion", family: .cat),
]

জেমির সমাধান থেকে প্রধান পার্থক্য হ'ল বৈশিষ্ট্যের অ্যাক্সেসটি ক্লাসে স্থির / উদাহরণ পদ্ধতিগুলির চেয়ে ইনলাইনটিকে সংজ্ঞায়িত করা হয়। যেমন $0.familyপরিবর্তে Animal.familyCompare। এবং আরোহী / উতরাই ওভারলোডেড অপারেটরের পরিবর্তে প্যারামিটার দ্বারা নিয়ন্ত্রিত হয়। আমার সমাধান ব্যবহার করে নির্মিত যেহেতু জেমি এর সমাধান এরে থাকা একটি এক্সটেনশন যোগ করা sort/ sortedপদ্ধতি কিন্তু দুটি অতিরিক্ত বেশী সংজ্ঞায়িত করা প্রয়োজন: compareএবং comparisons

সম্পূর্ণতার জন্য, আমার সমাধানটি হ্যামিশের টিপল সমাধানের সাথে কীভাবে তুলনা করে তা এখানে । প্রদর্শনের জন্য আমি একটি বুনো উদাহরণ ব্যবহার করব যেখানে আমরা (name, address, profileViews)হামিশের সমাধান অনুসারে লোককে বাছাই করতে চাই তুলনা শুরুর আগে ঠিক একবারে property টি সম্পত্তির মানগুলির প্রতিটি মূল্যায়ন করব। এটি পছন্দসই বা নাও থাকতে পারে। উদাহরণস্বরূপ, ধরে profileViewsনেওয়া একটি ব্যয়বহুল নেটওয়ার্ক কল যা profileViewsএটি একেবারে প্রয়োজনীয় না হলে আমরা কল এড়াতে চাই । আমার সমাধান এবং profileViewsপর্যন্ত মূল্যায়ন এড়াতে হবে । যাইহোক, যখন এটি মূল্যায়ন করে তখন সম্ভবত এটি একবারের চেয়ে আরও অনেক বার মূল্যায়ন করবে।$0.name == $1.name$0.address == $1.addressprofileViews


1

কেমন:

contacts.sort() { [$0.last, $0.first].lexicographicalCompare([$1.last, $1.first]) }

lexicographicallyPrecedesঅ্যারেতে সমস্ত ধরণের একই হওয়া দরকার। উদাহরণস্বরূপ [String, String]। ওপি সম্ভবত যা চায় তা হল মিশ্রিতকরণ এবং প্রকারের সাথে মেলা: [String, Int, Bool]যাতে তারা করতে পারে [$0.first, $0.age, $0.isActive]
সংবেদনশীল

-1

যা সুইফট 3 এ আমার অ্যারে [স্ট্রিং] এর জন্য কাজ করেছিল এবং এটি সুইফট 4-এ মনে হচ্ছে ঠিক আছে

array = array.sorted{$0.compare($1, options: .numeric) == .orderedAscending}

উত্তর দেওয়ার আগে আপনি প্রশ্নটি পড়েছেন? একাধিক পরামিতি অনুসারে বাছাই করুন, আপনি যা উপস্থাপন করছেন তা নয়।
ভিভ করুন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.