简体   繁体   中英

Swift - Sorting array of dollar values

I have an array of deals formatted like this:

"$2.25 Drink A"

"$5 Drink B"

"$10 Drink C"

etc

and I want to sort them by dollar amount.

    deals.sort {
        var first = $0.deal as String
        var second = $1.deal as String

        var myArr1 = first.componentsSeparatedByString(" ")
        var myArr2 = second.componentsSeparatedByString(" ")

        var formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle

        if let price1 = formatter.numberFromString(myArr1[0]) as NSNumber! {
            if let price2 = formatter.numberFromString(myArr2[0]) as NSNumber!{
                return first < second
            }
        }
        return false
    }

This is working correctly for values like $4.25 and anything one digit. If I try something like $10.25 it doesn't sort correctly.

Here's the playground I'm using the test the code

import UIKit


var deals: [(deal:String, bar:String)] = []

deals.append(deal: "$0.95" as String, bar: "bar" as String)
deals.append(deal: "$2.95" as String, bar: "bar" as String)
deals.append(deal: "$11.95" as String, bar: "bar" as String)
deals.append(deal: "$3.95" as String, bar: "bar" as String)


deals.sort {
    var first = $0.deal as String
    var second = $1.deal as String

    var myArr1 = first.componentsSeparatedByString(" ")
    var myArr2 = second.componentsSeparatedByString(" ")

    var formatter = NSNumberFormatter()
    formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle

    if let price1 = formatter.numberFromString(myArr1[0]) as NSNumber! {
        if let price2 = formatter.numberFromString(myArr2[0]) as NSNumber!{
            return first < second
        }
    } 
    return false
}

for deal in deals{
    print("\(deal.deal)\n")
}

EDIT : I know you've already accepted an answer, but FWIW, based on your own question edit, I've updated my answer below to show you how your playground code had to be changed to make my initial suggestion work.

deals.sort{
    let myArr1 = $0.deal.componentsSeparatedByString(" ")
    let myArr2 = $1.deal.componentsSeparatedByString(" ")
    let formatter = NSNumberFormatter()
    formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle

    if let price1 = formatter.numberFromString(myArr1[0]) {
        if let price2 = formatter.numberFromString(myArr2[0]) {
            return price1.floatValue < price2.floatValue
        }
    }
    return false
}

Another suggestion was that you could do even simpler if you had a Deal class, with a specific property that returned the float value of the deal, like this:

var dealValue: Float {
    get {
        let myArr = self.deal.componentsSeparatedByString(" ")
        let formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
        if let price = formatter.numberFromString(myArr[0]) {
            return price.floatValue
        } else {
            return 0
        }
    }
}

Then your previous code would simply become:

deals.sort { $0.dealValue < $1.dealValue }

The root of your problem is that you're sorting alphabetically rather than numerically. Numerically, 4.25 sorts before 10.25 because 4.25 < 10.25 . Alphabetically, 10.99 comes before 4.25 because the character code for 1 is less than that for 4 . To fix the problem, you obviously need to somehow obtain the number that corresponds to the price of the deal.

You could write a method that extracts the price from the record and returns it as a number, which you can then compare correctly. Better, store each deal as a dictionary or other structure so that the price is already broken out as a separate value.

I think you should store it as a Double and format it as currency when displaying it.

extension Double {
    var currency:String {
        let formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
        return formatter.stringFromNumber(self)!
    }
}
var deals: [(deal:Double, bar:String)] = []
deals.append(deal: 0.95 , bar: "bar")
deals.append(deal: 2.95 , bar: "bar")
deals.append(deal: 11.95, bar: "bar")
deals.append(deal: 3.95, bar: "bar")


deals.sort {$0.deal<$1.deal}

for deal in deals{
    print("\(deal.deal.currency)\n")
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM