So at first this seemed like a pretty straight-forward problem to solve, but there are some little catches i found, and my current end-solution is really ugly, so I'm curious to see what you guys can come up with
I have a class, OptionalObject
.
It has four properties,
let prop1: String?
let prop2: String?
let prop3: String?
let prop4: String?
I then have an array of a thousand of these OptionalObject
objects, and I'm guaranteed that there are no two objects with the exact same properties.
EX: (OptionalObject: prop1, prop2, prop3, prop4
Obj1: ABC, 123, Hello, Goodbye
Obj2: DEF, 456, nil, nil
Obj3: nil, nil, Hello, Goodbye
Obj4: nil, nil, Hello, nil
Obj5: ABC, nil, nil, nil
Obj6: ABC, nil, Hello, Goodbye
Obj7: DEF, 123, nil, Goodbye
Obj8: DEF, nil, nil, nil
...
and then I have a singular object of another class that has all 4 Strings (non-optional)
(ConcreteObject: arg1: String, arg2: String, arg3: String, arg4: String)
I want to find the best matching OptionalObject
to my ConcreteObject
, based on these four properties.
Which I can think of two ways to do it, one is to use filter
on all OptionalObjects
, the other is to manually enumerate over all OptionalObjects
, have nested if
statements to check properties (which is effectively the same as filter
anyways)
If I were to filter, it could be something like this:
let matchingOptionalObject = optionalObjectsArray.filter {return $0.prop1 == arg1 && $0.prop2 == arg2 && $0.prop3 == arg3 && $0.prop4 == arg4}
and boom I now have one object that matches... but only if it's an exact match.
If my ConcreteObject
has (DEF, 123, Hello, Goodbye)
I wouldn't get any matches, because no OptionalObjects
match exactly.
I would expect a return of Obj3, Obj4, Obj7, Obj8
So then naturally I think OK, let's first look at which arguments we have as non-nil, and then construct a query accordingly.
For this example, I'm going to pretend there's only two properties so it's easier to understand:
let matchingOptionalObject = optionalObjectsArray.filter {
if $0.prop1 != nil {
if $0.prop2 != nil {
return $0.prop1 == arg1 && $0.prop2 == arg2
} else {
return $0.prop1 == arg1
}
} else {
if $0.prop2 != nil {
return $0.prop2 == arg2
} else {
return false
}
}
}
But then the problem is that because there are 4 properties, there are like at least 10 different possibilities of unique nil
arguments that we need to cover, and this becomes a really really ugly
Which is what I currently have, I have a bunch of ugly if
statements checking the combination of nil
arguments, and then constructing a filter
query accordingly...
Which OK, we need to move on, so I guess we can deal with it and open an issue for figuring out a better solution later, but then there is one more requirement that makes this solution not work...
Which is that each property has a different weight.
Two Rules for picking the best match when there are multiple matches:
1) Pick the match that has the most properties that match
2) If the matches have the same number of properties that match, pick the match that has the highest weight.
Prop1 has the highest weight
Prop2 has the lowest
So with the example of ConcreteObject
: (DEF, 123, Hello, Goodbye)
Matched OptionalObjects
:
Obj3: nil, nil, Hello, Goodbye
Obj4: nil, nil, Hello, nil
Obj7: DEF, 123, nil, Goodbye
Obj8: DEF, nil, nil, nil
We would pick Obj7
as the best match because it has 3 matching properties
But let's say for some other example with a new ConcreteObject
and a new set of OptionalObjects
, we have this match:
Our new Matched OptionalObjects
:
New1: nil, 999, nil, NiHao
New2: XYZ, 999, nil, nil
We would pick New2
, because even though New1
and New2
both have 2 matching properties, New2
has the matching properties of higher weight.
So, there's the dilemma.
I'm hoping that I'm just not remembering some key concepts years ago in my undergrad algorithms class, and that there's some clean solution (maybe even something that Swift provides), but I'm near my wit's end-- so really any suggestions or insight anybody has is more than welcome