Skip to content

Commit d14e558

Browse files
committed
feat: dictionary search list
1 parent 3e1986d commit d14e558

4 files changed

Lines changed: 217 additions & 28 deletions

File tree

Help.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
/* Begin PBXBuildFile section */
1010
5E023E89268364C3002465D8 /* ArrayEnumerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E023E88268364C3002465D8 /* ArrayEnumerated.swift */; };
1111
5E023E8B2683692F002465D8 /* ArrayZip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E023E8A2683692F002465D8 /* ArrayZip.swift */; };
12-
5E023E8F26863070002465D8 /* DictionaryReduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E023E8E26863070002465D8 /* DictionaryReduce.swift */; };
12+
5E023E8F26863070002465D8 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E023E8E26863070002465D8 /* Dictionary.swift */; };
1313
5E2CF7C1266E20AE007BB2EB /* UnwindSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E2CF7C0266E20AE007BB2EB /* UnwindSegue.swift */; };
1414
5E2CF7C5266E242E007BB2EB /* segue-002.png in Resources */ = {isa = PBXBuildFile; fileRef = 5E2CF7C3266E242E007BB2EB /* segue-002.png */; };
1515
5E2CF7C6266E242E007BB2EB /* segue-001.png in Resources */ = {isa = PBXBuildFile; fileRef = 5E2CF7C4266E242E007BB2EB /* segue-001.png */; };
@@ -57,7 +57,7 @@
5757
/* Begin PBXFileReference section */
5858
5E023E88268364C3002465D8 /* ArrayEnumerated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayEnumerated.swift; sourceTree = "<group>"; };
5959
5E023E8A2683692F002465D8 /* ArrayZip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayZip.swift; sourceTree = "<group>"; };
60-
5E023E8E26863070002465D8 /* DictionaryReduce.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryReduce.swift; sourceTree = "<group>"; };
60+
5E023E8E26863070002465D8 /* Dictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = "<group>"; };
6161
5E2CF7C0266E20AE007BB2EB /* UnwindSegue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnwindSegue.swift; sourceTree = "<group>"; };
6262
5E2CF7C3266E242E007BB2EB /* segue-002.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "segue-002.png"; sourceTree = "<group>"; };
6363
5E2CF7C4266E242E007BB2EB /* segue-001.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "segue-001.png"; sourceTree = "<group>"; };
@@ -231,7 +231,7 @@
231231
5E72DD5D266A76EE00A8E543 /* Guard.swift */,
232232
5E023E88268364C3002465D8 /* ArrayEnumerated.swift */,
233233
5E023E8A2683692F002465D8 /* ArrayZip.swift */,
234-
5E023E8E26863070002465D8 /* DictionaryReduce.swift */,
234+
5E023E8E26863070002465D8 /* Dictionary.swift */,
235235
5EF5E01426F72FE40068A717 /* EnumDataModel.swift */,
236236
);
237237
path = WorkingCode;
@@ -361,7 +361,7 @@
361361
5E8385802667B63900ACA770 /* MARK.swift in Sources */,
362362
5EAC17FA26808458006EC7CD /* PassDataClosure.swift in Sources */,
363363
5EAC92BE26BC0BCD00A6198C /* Source.swift in Sources */,
364-
5E023E8F26863070002465D8 /* DictionaryReduce.swift in Sources */,
364+
5E023E8F26863070002465D8 /* Dictionary.swift in Sources */,
365365
5EAF0B81268C5F4300D92322 /* LaunchScreen.swift in Sources */,
366366
5E8385572667635000ACA770 /* ViewController.swift in Sources */,
367367
5E66D43626694663001CB8F0 /* FailableInitializers.swift in Sources */,

Help/WorkingCode/Dictionary.swift

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
//
2+
// Dictionary.swift
3+
// Help
4+
//
5+
// Created by Sergey Lukaschuk on 25.06.2021.
6+
//
7+
8+
import Foundation
9+
10+
11+
// MARK: Dictionary Reduce
12+
13+
14+
let fruits = ["🍏", "🍓", "🍒", "🍌", "🍏", "🍒", "🍌", "🍌", "🍌", "🍒", "🍒", "🍌", "🍓", "🍓"]
15+
16+
let fruitsCount = fruits.reduce(into: [:]) { counts, fruit in
17+
counts[fruit, default: 0] += 1
18+
}
19+
20+
// fruitsCount
21+
// ["🍒": 4, "🍏": 2, "🍓": 3, "🍌": 5]
22+
// [String : Int]
23+
24+
25+
26+
// MARK: Dictionary Search List
27+
28+
struct Product: Hashable {
29+
let id: String; // unique identifier
30+
let name: String;
31+
let producer: String;
32+
33+
static func ==(lhs: Product, rhs: Product) -> Bool {
34+
return lhs.id == rhs.id
35+
}
36+
}
37+
38+
protocol Library {
39+
/**
40+
Adds a new product object to the Library.
41+
- Parameter product: product to add to the Library
42+
- Returns: false if the product with same id already exists in the Library, true – otherwise.
43+
*/
44+
func addNewProduct(product: Product) -> Bool;
45+
46+
/**
47+
Deletes the product with the specified id from the Library.
48+
- Returns: true if the product with same id existed in the Library, false – otherwise.
49+
*/
50+
func deleteProduct(id: String) -> Bool;
51+
52+
/**
53+
- Returns: 10 product names containing the specified string. If there are several products with the same name, producer's name is appended to product's name.
54+
*/
55+
func listProductsByName(searchString: String) -> Set<String>;
56+
57+
/**
58+
- Returns: 10 product names whose producer contains the specified string, ordered by producers.
59+
*/
60+
func listProductsByProducer(searchString: String) -> [String];
61+
}
62+
63+
class LibraryRepository: Library {
64+
private var products = [String: Product]()
65+
66+
func addNewProduct(product: Product) -> Bool {
67+
return self.products.updateValue(product, forKey: product.id) == nil
68+
}
69+
70+
func deleteProduct(id: String) -> Bool {
71+
return self.products.removeValue(forKey: id) != nil
72+
}
73+
74+
func listProductsByName(searchString: String) -> Set<String> {
75+
return self.products
76+
.filter({ $1.name.contains(searchString) })
77+
.prefix(10)
78+
.reduce(into: Set<String>()) { (productNames, product) in
79+
if products.filter({ $1.name == product.value.name }).count > 1 {
80+
productNames.insert("\(product.value.producer) - \(product.value.name)")
81+
return
82+
}
83+
productNames.insert(product.value.name)
84+
}
85+
}
86+
87+
func listProductsByProducer(searchString: String) -> [String] {
88+
return self.products
89+
.filter({ $1.producer.contains(searchString) })
90+
.sorted(by: { $0.value.producer > $1.value.producer })
91+
.prefix(10)
92+
.map { $0.value.name }
93+
}
94+
}
95+
96+
func test(lib: Library) {
97+
assert(!lib.deleteProduct(id: "1"))
98+
assert(lib.addNewProduct(product: Product(id: "1", name: "1", producer: "Lex")))
99+
assert(!lib.addNewProduct(product: Product(id: "1", name: "any name because we check id only", producer: "any producer")))
100+
assert(lib.deleteProduct(id: "1"))
101+
assert(lib.addNewProduct(product: Product(id: "3", name: "Some Product3", producer: "Some Producer2")))
102+
assert(lib.addNewProduct(product: Product(id: "4", name: "Some Product1", producer: "Some Producer3")))
103+
assert(lib.addNewProduct(product: Product(id: "2", name: "Some Product2", producer: "Some Producer2")))
104+
assert(lib.addNewProduct(product: Product(id: "1", name: "Some Product1", producer: "Some Producer1")))
105+
assert(lib.addNewProduct(product: Product(id: "5", name: "Other Product5", producer: "Other Producer4")))
106+
assert(lib.addNewProduct(product: Product(id: "6", name: "Other Product6", producer: "Other Producer4")))
107+
assert(lib.addNewProduct(product: Product(id: "7", name: "Other Product7", producer: "Other Producer4")))
108+
assert(lib.addNewProduct(product: Product(id: "8", name: "Other Product8", producer: "Other Producer4")))
109+
assert(lib.addNewProduct(product: Product(id: "9", name: "Other Product9", producer: "Other Producer4")))
110+
assert(lib.addNewProduct(product: Product(id: "10", name: "Other Product10", producer: "Other Producer4")))
111+
assert(lib.addNewProduct(product: Product(id: "11", name: "Other Product11", producer: "Other Producer4")))
112+
113+
var byNames: Set<String> = lib.listProductsByName(searchString: "Product")
114+
assert(byNames.count == 10)
115+
116+
byNames = lib.listProductsByName(searchString: "Some Product")
117+
assert(byNames.count == 4)
118+
assert(byNames.contains("Some Producer3 - Some Product1"))
119+
assert(byNames.contains("Some Product2"))
120+
assert(byNames.contains("Some Product3"))
121+
assert(!byNames.contains("Some Product1"))
122+
assert(byNames.contains("Some Producer1 - Some Product1"))
123+
124+
var byProducer: [String] = lib.listProductsByProducer(searchString: "Producer")
125+
assert(byProducer.count == 10)
126+
127+
byProducer = lib.listProductsByProducer(searchString: "Some Producer")
128+
assert(byProducer.count == 4)
129+
assert(byProducer[0] == "Some Product1")
130+
assert(byProducer[1] == "Some Product2" || byProducer[1] == "Some Product3")
131+
assert(byProducer[2] == "Some Product2" || byProducer[2] == "Some Product3")
132+
assert(byProducer[3] == "Some Product1")
133+
}
134+
135+
//test(lib: LibraryRepository())

Help/WorkingCode/DictionaryReduce.swift

Lines changed: 0 additions & 22 deletions
This file was deleted.

README.md

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ In this project, I have collected various best practices and iOS development tip
2929
- [Guard](#guard)
3030
- [Array Enumerated](#array-enumerated)
3131
- [Array Zip](#array-zip)
32-
- [Dictionary Reduce](#dictionary-reduce)
32+
- [Dictionary](#dictionary)
3333
- [Enum Data Model](#enum-data-model)
3434

3535

@@ -738,9 +738,11 @@ print(newArray)
738738
```
739739

740740

741-
### [Dictionary Reduce](https://github.com/lgreydev/Help/blob/master/Help/WorkingCode/DictionaryReduce.swift)
741+
### [Dictionary](https://github.com/lgreydev/Help/blob/master/Help/WorkingCode/Dictionary.swift)
742742
[documentation](https://developer.apple.com/documentation/swift/array/3126956-reduce)
743743

744+
**Dictionary Reduce**
745+
744746
Returns the result of combining the elements of the sequence using the given closure.
745747

746748
```swift
@@ -756,6 +758,80 @@ fruitsCount // ["🍒": 4, "🍏": 2, "🍓": 3, "🍌": 5]
756758

757759
```
758760

761+
**Dictionary Search List**
762+
763+
```
764+
struct Product: Hashable {
765+
let id: String; // unique identifier
766+
let name: String;
767+
let producer: String;
768+
769+
static func ==(lhs: Product, rhs: Product) -> Bool {
770+
return lhs.id == rhs.id
771+
}
772+
}
773+
774+
protocol Library {
775+
/**
776+
Adds a new product object to the Library.
777+
- Parameter product: product to add to the Library
778+
- Returns: false if the product with same id already exists in the Library, true – otherwise.
779+
*/
780+
func addNewProduct(product: Product) -> Bool;
781+
782+
/**
783+
Deletes the product with the specified id from the Library.
784+
- Returns: true if the product with same id existed in the Library, false – otherwise.
785+
*/
786+
func deleteProduct(id: String) -> Bool;
787+
788+
/**
789+
- Returns: 10 product names containing the specified string. If there are several products with the same name, producer's name is appended to product's name.
790+
*/
791+
func listProductsByName(searchString: String) -> Set<String>;
792+
793+
/**
794+
- Returns: 10 product names whose producer contains the specified string, ordered by producers.
795+
*/
796+
func listProductsByProducer(searchString: String) -> [String];
797+
}
798+
799+
class LibraryRepository: Library {
800+
private var products = [String: Product]()
801+
802+
func addNewProduct(product: Product) -> Bool {
803+
return self.products.updateValue(product, forKey: product.id) == nil
804+
}
805+
806+
func deleteProduct(id: String) -> Bool {
807+
return self.products.removeValue(forKey: id) != nil
808+
}
809+
810+
func listProductsByName(searchString: String) -> Set<String> {
811+
return self.products
812+
.filter({ $1.name.contains(searchString) })
813+
.prefix(10)
814+
.reduce(into: Set<String>()) { (productNames, product) in
815+
if products.filter({ $1.name == product.value.name }).count > 1 {
816+
productNames.insert("\(product.value.producer) - \(product.value.name)")
817+
return
818+
}
819+
productNames.insert(product.value.name)
820+
}
821+
}
822+
823+
func listProductsByProducer(searchString: String) -> [String] {
824+
return self.products
825+
.filter({ $1.producer.contains(searchString) })
826+
.sorted(by: { $0.value.producer > $1.value.producer })
827+
.prefix(10)
828+
.map { $0.value.name }
829+
}
830+
}
831+
```
832+
833+
834+
759835
### [Enum Data Model](https://github.com/lgreydev/Help/blob/master/Help/WorkingCode/EnumDataModel.swift)
760836

761837
```swift

0 commit comments

Comments
 (0)