像购物清单一样格式化数组
Formatting an array like a shopping list
我有一个格式如下的数组:
["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"]
如果我使用字典,则不能有重复项。我该如何处理?
我会制作一个结构来表示项目 name/price 对(以及未来可能的其他数据,例如库存数量)。
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 Trousers: £15.5", "1x Shoes: £50.0", "1x Jumper: £12.99"]
您可以使用这个结构,它接受您的字符串作为构造函数的参数:
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)
}
对于简单的对,您不需要结构或 class;使用元组数组:
var shoppingList = [("Trousers", 15.50), ("Trousers", 15.50), ("Jumper", 12.99), ("Shoes", 50.00)]
for (name, price) in shoppingList {
print(name, price)
}
我有一个格式如下的数组:
["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"]
如果我使用字典,则不能有重复项。我该如何处理?
我会制作一个结构来表示项目 name/price 对(以及未来可能的其他数据,例如库存数量)。
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 Trousers: £15.5", "1x Shoes: £50.0", "1x Jumper: £12.99"]
您可以使用这个结构,它接受您的字符串作为构造函数的参数:
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)
}
对于简单的对,您不需要结构或 class;使用元组数组:
var shoppingList = [("Trousers", 15.50), ("Trousers", 15.50), ("Jumper", 12.99), ("Shoes", 50.00)]
for (name, price) in shoppingList {
print(name, price)
}