Sorting based on Future Result

2019-02-28 15:45发布

问题:

I've trying to sort a list by a future boolean.

I have a list of IDs and I need to query an external service to find out if there's contextual information behind them. The method I use to do this returns an optional future.

By using the partition method I hoped to create two lists of IDs, one with contextual information and one without.

The following answer on here provided a lot of help for this: Scala - sort based on Future result predicate

I now have an rough, untested method that looks like so,

val futureMatch = listOfIds.map( b => b.map{ j =>
  getContext(j).map{ k =>
    Map( j -> k)
  }
}).map(Future.sequence(_)).flatMap(identity)

val partitionedList = futureMatch.map(_.partition{
  case (k, Some(v)) => true
  case _ => false
})

So as advised in the other question, I'm attempting to get all my answers at the same level, and then using Future.sequence and flatMap(identity) to flatten nested layers of futures.

The problem is this doesn't feel very efficient.

Ideally the successful list would have a signature of List[Map[String, String]] not List[Map[String, Option[String]] and the failed list would just be a list of Strings, so it'd only need to be one dimensional. As it currently stands I have two identical list signatures which have some redundancy. For example in the successful list, I know this is going exist so it doesn't need to be an option.

Any ideas how I could achieve this structure and produce two lists with different signatures or even if this is the most efficient way.

Thanks.

EDIT: Looking at the signature for partition it looks like I can only produce two lists of the same signature, so a different signature is probably too much to ask. I guess I can just flatten the list afterwards.

回答1:

I found a suitable solution in the comments of the question I linked too.

val (matched, unmatched) =
  finalMatch.foldLeft(List.empty[Map[String, String]], List.empty[String]) {
     case ((matched, unmatched), p) => p match {
       case m:Map[String, String] => (m :: matched, unmatched)
       case s:String => (matched, s :: unmatched)
     }
   }

The only issue with this is it leads to type erasure. I've opened another question to discuss this issue.

Dealing with Type Erasure with foldLeft

Thanks all.