Reputation: 879
I would like to generate a shopping list from an array of products. I have an entity "Product" in Core Data that has name (String) and amount (Int) as its properties. I am in the moment where I have an array of products with some duplicates, something like that:
var products : [Product] = [Apple, Egg, Orange, Apple, Orange, Banana, Egg, Egg]
How can I filter such array to get sums of amount of specific products? I would like to get as a result the list of products with their amounts like: Apple: 4, Banana: 3, Egg: 7, Orange 2
. I know that I can make a Set from that Array to avoid duplicates, but I don't know how to sum products' amount before that.
Upvotes: 2
Views: 1737
Reputation: 6171
You can do like this:
enum Fruit {
case Orange
case Lemon
case Potato
}
let fruits = [Fruit.Orange, .Lemon, .Potato, .Orange, .Lemon, .Orange]
let fruitSet = Set(fruits)
var result = [Fruit: Int]()
for fruit in fruitSet {
result[fruit] = fruits.filter { $0 == fruit }.count
}
someone please explain why my answer is not useful? The output will be [Fruit.Orange: 3, Fruit.Lemon: 2, Fruit.Potato: 1]
Upvotes: -1
Reputation: 48599
enum Fruit {
case Orange
case Lemon
case Potato
}
let fruits = [Fruit.Orange, .Lemon, .Potato, .Orange, .Lemon, .Orange]
var result: [Fruit: Int] = [:]
for fruit in fruits {
if let count = result[fruit] {
result[fruit] = count + 1
}
else {
result[fruit] = 1
}
}
print(result)
--output:--
[Fruit.Potato: 1, Fruit.Orange: 3, Fruit.Lemon: 2]
Or, even:
num Product {
case Apple
case Egg
case Orange
case Banana
}
let products: [Product] = [.Apple, .Egg, .Orange, .Apple, .Orange, .Banana, .Egg, .Egg]
let result = products.reduce([:]) { (var map, product) -> [Product: Int] in
if let count = map[product] {
map[product] = count + 1
}
else {
map[product] = 1
}
return map
}
print(result)
--output:--
[Product.Orange: 2, Product.Apple: 2, Product.Egg: 3, Product.Banana: 1]
Upvotes: 0
Reputation: 2628
enum Product {
case Apple
case Egg
case Orange
case Banana
}
let products: [Product] = [.Apple, .Egg, .Orange, .Apple, .Orange, .Banana, .Egg, .Egg]
products.reduce([:]) { (map, product) -> [Product: Int] in
var updatedMap = map
if let value = map[product] {
updatedMap[product] = value + 1
}
else {
updatedMap[product] = 1
}
return updatedMap
} //[Orange: 2, Apple: 2, Egg: 3, Banana: 1]
same with strings:
let products: [String] = ["Apple", "Egg", "Orange", "Apple", "Orange", "Banana", "Egg", "Egg"]
products.reduce([:]) { (map, product) -> [String: Int] in
var updatedMap = map
if let value = map[product] {
updatedMap[product] = value + 1
}
else {
updatedMap[product] = 1
}
return updatedMap
} // ["Apple": 2, "Egg": 3, "Orange": 2, "Banana": 1]
Or by extension for all hashable sequence types:
extension SequenceType where Generator.Element: Hashable {
func countElements() -> [Generator.Element : Int] {
return reduce([:]) { (map, element) -> [Generator.Element : Int] in
var updatedMap = map
if let value = map[element] {
updatedMap[element] = value + 1
}
else {
updatedMap[element] = 1
}
return updatedMap
}
}
}
products.countElements() //["Apple": 2, "Egg": 3, "Orange": 2, "Banana": 1]
Upvotes: 3