Filter array of objects with multiple criteria and types in Swift -
i trying complex filtering in app , point don't know next. data consistes of array of dictionaries values in each of dictionaries can string, int or [string].
let person1: [string : any] = ["first_name" : "john", "last_name" : "smith", "age" : 21, "skills" : ["c#", "java", "swift"]] let person2: [string : any] = ["first_name" : "kim", "last_name" : "smith", "age" : 28, "skills" : ["java", "swift"]] let person3: [string : any] = ["first_name" : "kate", "last_name" : "bell", "age" : 24, "skills" : ["c#"]] var people = [person1, person2, person3] i let user choose how filter data , create dictionary of filter criteria. dictionary can have number of keys , values.
let filters: [string : [any]] = ["age" : [28, 24], "skills" : ["java", "swift"]] in example want show persons age 28 or 24 , have skills of java or swift, person2
here have far works int values:
for (key, values) in filters { var filtereditems = people.filter { var match = false filtervalue in values { if $0[key] as! int == filtervalue as! int { match = true break } else { match = false } } return match } people = filtereditems }
here's how this:
struct person { let firstname: string let lastname: string let age: int let skills: [string] enum filter { enum filtertype<t: hashable> { case one(of: [t]) case all(of: [t]) // match against property that's single value func matches(_ value: t) -> bool { switch self { case .one(let filtervalues): return filtervalues.contains(value) case .all(let filtervalues): return filtervalues.count == 1 && filtervalues[0] == value } } // match against property that's list of values func matches(_ values: [t]) -> bool { switch self { case .one(let filtervalues): return !set(filtervalues).intersection(values).isempty case .all(let filtervalues): return set(filtervalues).issuperset(of: values) } } } case age(is: filtertype<int>) case skills(is: filtertype<string>) func matches(_ p: person) -> bool { switch self { case .age(let filtervalues): return filtervalues.matches(p.age) case .skills(let filtervalues): return filtervalues.matches(p.skills) } } } } extension array element == person.filter { func atleastonematch(_ p: person) -> bool { filter in self filter.matches(p) { return true } return false } func matchesall(_ p: person) -> bool { filter in self !filter.matches(p) { return false } return true } } let people = [ person( firstname: "john", lastname : "smith", age: 21, skills: ["c#", "java", "swift"] ), person( firstname: "kim", lastname : "smith", age: 28, skills: ["java", "swift"] ), person( firstname: "kate", lastname: "bell", age: 24, skills: ["c#"] ), ] let filters: [person.filter] = [ .age(is: .one(of: [28, 24])), .skills(is: .one(of: ["java", "swift"])), ] let peoplewhomatchallfilters = people.filter(filters.matchesall) print(peoplewhomatchallfilters) let peoplewhomatchatleastonefilter = people.filter(filters.atleastonematch) print(peoplewhomatchatleastonefilter) i've extended filtering capability able specify wether values of filter should matched (e.g. person must know java , swift , c#) or @ least 1 (e.g. person must know @ least java or swift or c#)
Comments
Post a Comment