6

Maybe a stupid question but I just don't get it.

I have a Set<Either<Failure, Success>> and want to output a Set<Success> with Arrow-kt.

sschrass
  • 7,014
  • 6
  • 43
  • 62

1 Answers1

8

You can map the set like this for right:

val successes = originalSet.mapNotNull { it.orNull() }.toSet()

or if you want the lefts:

val failures = originalSet.mapNotNull { it.swap().orNull() }.toSet()

The final toSet() is optional if you want to keep it as a Set as mapNotNull is an extension function on Iterable and always returns a List

PS: No stupid questions :)

Update: It can be done avoiding nullables:

val successes = originalSet
  .map { it.toOption() }
  .filter { it is Some }
  .toSet()

We could potentially add Iterable<Option<A>>.filterSome and Iterable<Either<A, B>.mapAsOptions functions.

Update 2:

That last example returns a Set<Option<Success>>. If you want to unwrap the results without using null then one thing you can try is to fold the Set:

val successes = originalSet
  .fold(emptySet<Success>()) { acc, item -> 
    item.fold({ acc }, { acc + it })
  }

This last option (unintended pun) doesn't require the use of Option.

pablisco
  • 14,027
  • 4
  • 48
  • 70
  • 1
    is it just me or is calling a filter function mapNotNull not deeply confusing? – jk. Mar 13 '19 at 17:25
  • @jk It's not a `filter` function, it's short for `map().filterNotNull()`. Similar to having `flatMap()` being short for `map().flatten()` (I guess that one is strange since the order of names changes) – pablisco Mar 13 '19 at 17:48
  • Thanks a lot! I am not quite happy with this, but it does the trick. – sschrass Mar 14 '19 at 09:50
  • 1
    I mean I have Option or Either to not introduce `null` but this forces me to do so, at least in a narrow scope. – sschrass Mar 14 '19 at 09:58
  • @sschrass I've added an example without `null` – pablisco Mar 14 '19 at 11:31
  • Cool, because it looks more idiomatic, This is what I tried with .filter { it is Either.Right}. – sschrass Mar 18 '19 at 08:33