【问题标题】:Formatting an array like a shopping list像购物清单一样格式化数组
【发布时间】:2017-05-15 04:27:27
【问题描述】:

我有一个格式如下的数组:

["Trousers : 15.50", "Trousers : 15.50", "Jumper : 12.99", "Shoes: 50.00"]

我想这样格式化:

["2x Trousers : 31.00", "1x Jumper : 12.99", "1x Shoes: 50.00"]

我尝试使用以下格式进行格式化:

 var counts: [String:Int] = [:]
 var shoppingList = ["Trousers : 15.50", "Trousers : 15.50", "Jumper : 12.99", "Shoes: 50.00"]
 var formattedShoppingList = [String]()

     for item in shoppingList {
         counts[item] = (counts[item] ?? 0) + 1
     }


     for (key, value) in counts {

         let display:String = String(value) + "x " + key
         formattedShoppingList.append(display)

     }

但我明白了

["2x Trousers : 15.50", "1x Jumper : 12.99", "1x Shoes: 50.00"]

如果我使用字典,我不能有重复。我该如何处理?

【问题讨论】:

  • 我的猜测var shoppingList = ["Trousers : 15.50", "Trousers : 15.50", "Jumper : 12.99", "Shoes: 50.00"]
  • 我会将所有这些数据分组到 structclass 中,而不是使用字典,然后您可以使用一些属性来获取项目的大小。 struct Grouping { var Key:String var values:[String] }
  • 你知道[Trousers : 15.50, Trousers : 15.50, Jumper : 12.99, Shoes: 50.00] 不是一个数组吗?
  • 对不起,我错过了报价

标签: arrays swift swift3 shopping-cart


【解决方案1】:

我会创建一个结构来表示商品名称/价格对(可能还有未来的其他数据,例如库存数量)。

struct Item: Hashable {
    let name: String
    let price: Double

    public var hashValue: Int { return name.hashValue ^ price.hashValue }

    public static func ==(lhs: Item, rhs: Item) -> Bool {
        return lhs.name == rhs.name && rhs.price == rhs.price
    }
}

let shoppingList = [
    Item(name: "Trousers", price: 15.50),
    Item(name: "Trousers", price: 15.50),
    Item(name: "Jumper", price: 12.99),
    Item(name: "Shoes", price: 50),
]

let counts = shoppingList.reduce([Item: Int]()){counts, item in
    var counts = counts
    counts[item] = (counts[item] ?? 0) + 1
    return counts
}

let formattedShoppingList = counts.map{ item, count in "\(count)x \(item.name): £\(item.price)" }

print(formattedShoppingList)

[“2x 裤子:15.5 英镑”,“1x 鞋子:50.0 英镑”,“1x 套头衫:12.99 英镑”]

【讨论】:

  • 如果我们添加 let formattedShoppingList = counts.map{ item, count in "(count)x (item.name): £(item.price * Double(count))" }
  • 请注意,您不应该使用像Double 这样的二进制浮点类型来表示货币值——而是使用Decimal。此外,在性能方面,简单的 for-in 循环比 reduce 更可取,因为 reduce 将在每次迭代时不必要地复制累积字典。
  • @Hamish 你对小数的看法是完全正确的,我本来想改变它,但最终忘记了。请您提出修改建议吗?
  • @Alexander 抱歉,我现在不在电脑旁,所以编辑你的帖子不太舒服
  • @Hamish 一样,哈哈
【解决方案2】:

你可以使用这个结构,它接受你的字符串作为构造函数的参数:

struct ShoppingItem: Hashable {
    let name: String
    let price: NSDecimalNumber

    //Expects a String in the form "ElementName : Price"
    init?(description: String) {
        let splitDescription = description.components(separatedBy: ":")

        guard splitDescription.count == 2 else { return nil }

        name = splitDescription[0].trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
        price = NSDecimalNumber(string: splitDescription[1])
    }

    public var hashValue: Int {
        return "\(name)\(price)".hashValue
    }
}
func ==(lhs: ShoppingItem, rhs: ShoppingItem) -> Bool {
    return lhs.hashValue == rhs.hashValue
}

有了它,你可以将你的购物清单转换成这样的购物清单(考虑到,这会丢弃它无法转换的项目,你可以检查 nil 项目以确保所有项目都可以转换) :

var shoppingItems = shoppingList.flatMap(ShoppingItem.init(description:))

然后,你只是做你之前所做的,只是在最后乘以价格:

var counts = [ShoppingItem: Int]()
for item in shoppingItems {
    counts[item] = (counts[item] ?? 0) + 1
}

for (key, value) in counts {
    let multipliedPrice = key.price.multiplying(by: NSDecimalNumber(value: value))
    let display = "\(value)x \(key.name) : \(multipliedPrice)"
    formattedShoppingList.append(display)
}

【讨论】:

    【解决方案3】:

    对于简单的对,您不需要结构或类;使用元组数组:

        var shoppingList = [("Trousers", 15.50), ("Trousers", 15.50), ("Jumper", 12.99), ("Shoes", 50.00)]
    
        for (name, price) in shoppingList {
            print(name, price)
        }
    

    【讨论】:

    • 这如何解决他的问题?如果我错了,请纠正我,但这应该只打印数组的每个元素,这并没有给他他喜欢的格式。
    猜你喜欢
    • 2018-12-16
    • 1970-01-01
    • 2013-11-30
    • 1970-01-01
    • 1970-01-01
    • 2020-08-06
    • 2018-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多