I'm facing a simple task, but struggle to solve it...
# arrow
b
I'm facing a simple task, but struggle to solve it elegantly. (To clarify: performance is not an issue). I have two
Set<X>
collections, and I want to see if they contain equal items. The challenge is that this equality must be tested by some external
isomorphic
function (which takes two arguments of type
X
) instead of the standard equality operator. Can someone point towards helpful ideas or tools in Kotlin/Arrow?
My initial idea was to have a Cartesian product which I zip, and then I can use
all
to force equality by the
isomorphic
function. I'm not sure if that's the best option though. Moreover, I can't seem to find anything in Arrow or Kotlin to perform a Cartesian product (like Python's
itertools.product
)
r
So you want to see if there’s a 1:1 mapping between all items of set A and set B? For example True A: 1, 2, 3 B: 3, 1, 2 False: A: 1, 2, 3 B: 2, 3, 4
b
Exactly. But to emphasize: equality among elements should be tested using the function
isomorphic
, not
==
.
r
Is that a function provided by arrow? I’m out of the loop
b
No, it's from the 3rd party library I'm working with. Its inner workings shouldn't matter, all you should need to know is that it returns
true
if it deems two elements equal, and
false
otherwise
r
Are the sets sorted?
b
Sets are unordered by definition, and for reasons tied to my use case you can assume no ordering is possible, so there's no possibility of (usefully) casting to some ordered collection type (like
List
)
I seemed to have found one way of doing it which seems okay only works if
A
is a subset of
B
, so that doesn't suffice, but:
Copy code
setA.all { a -> setB.any { b -> isomorphic(a, b) } }  // should be true
r
I think for an unordered set that’s the time complexity you’re stuck with.
b
Yes, probably so. I should note that performance is not an issue here though. It's really just a handful of elements in each set.
r
Ahh ok that’s good to know
If set B has elements that set A doesn’t have is that ok?
I don’t think that implementation would capture that
b
You're right. Thanks for catching that
r
I also don’t have my set theory vocabulary down so I may be wrong here but I think the right word for what you’re trying to determine is if the sets are injective
Might need to end up with something like this
Copy code
fun <T> Set<T>.containsAllIsomorphic(other: Set<T>) = this.all { a -> other.any { b -> isomorphic(a, b)} }
fun <T> Set<T>.isInjective(other: Set<T>) = this.containsAll(other) && other.containsAll(this)
Bad performance for large sets, but when data is small no big deal 🙂
1
b
Yes, that would work. I'm really hoping there's a nicer way than this, although it wouldn't be too bad.
Thanks for your help!
r
Anytime 🙂
b
One small improvement: instead of checking both sides, you can also check one side and make sure both sets have the same amount of elements.
r
True that would be smarter 🙂