2

I have an array of tuple, tuple contains array of struct Bill

let billDetails = [(name:String, bills:[Bill])]()

struct Bill {
    var date: Date
}

The inner array bills is already sorted by the date property. Now I want to sort the outer array based on the inner array's first object's date property.

How to do this without force unwrapping?

billDetails = billDetails.sorted(by: { $0.bills.first!.date < $1.bills.first!.date })

3
  • Need to check $0.bills.first != nil && $.bills.first != nil isn't? Commented May 11, 2019 at 12:01
  • 1
    Possibly helpful: stackoverflow.com/a/56073710/1187415. Commented May 11, 2019 at 12:11
  • @MartinR If it was Int, I would have used Int.min and Int.max. Didn't know about distantPast and distantFuture. Thanks Commented May 11, 2019 at 12:17

2 Answers 2

2

You need to decide where to put an item if its bills is empty. There is really only 2 options, either put them at the start of the array or at the back of the array.

You can use ?? to provide a default value of either distantFuture or distantPast depending on where you want the empty bills to go.

// empty bills last
billDetails.sort(by: { $0.bills.first?.date ?? Date.distantFuture < $1.bills.first?.date ?? Date.distantFuture })
// or empty bills first
billDetails.sort(by: { $0.bills.first?.date ?? Date.distantPast < $1.bills.first?.date ?? Date.distantPast })
Sign up to request clarification or add additional context in comments.

2 Comments

Can you give titles for your answers, which puts empty bills at first and which puts last. If I want to remove the items when its bills is empty, It it possible to do without using another filter function?
@arunsiva edited. You can’t remove stuff from an array with just a sort.
1

How about the following?

billDetails = billDetails.sorted(by: { lhs, rhs in
  guard !lhs.bills.isEmpty || !rhs.bills.isEmpty else {
    return false
  }

  if !lhs.bills.isEmpty, rhs.bills.isEmpty {
    return false
  }

  if lhs.bills.isEmpty, !rhs.bills.isEmpty {
    return true
  }

  return lhs.bills[0].date < rhs.bills[0].date
})

4 Comments

What happens when one element in billDetails contains empty bills? That one will be the first element after sorting?
Please check my edit. It should achieve your desired behavior. But you can easily change it if you want to empty bills in the end.
Thanks for your input. Giving default value seems more simple and readable
Agreed. But in the case you want to handle the case where both are empty and sort by a secondary field, just edit in the first guard. Anyways, I'm glad you could find your answer! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.