Skip to content

Instantly share code, notes, and snippets.

@halfninja
Created May 30, 2019 10:52
Show Gist options
  • Save halfninja/020e59a56f3b29d1fb9c158d3118a5da to your computer and use it in GitHub Desktop.
Save halfninja/020e59a56f3b29d1fb9c158d3118a5da to your computer and use it in GitHub Desktop.
/** Spread all items approximately equal between recipients. If there is a nonzero remainder N
* between the recipients, the first N recipients will receive an extra one each, so nobody will
* receive more than 1 than anyone else.
*
* Doesn't consider how many items a recipient may already be holding, so it won't seek to
* balance out recipients if they are currently unbalanced.
*
* @return Each recipient with a list of its allotted items
*/
object distribute {
def apply[N, A](recipients: Seq[N], items: Seq[A]): Seq[(N, Seq[A])] = {
// We do .toList in a couple of places to handle where the incoming Seq is a Stream,
// which has confusing lazy properties especially with iterators. So don't remove them
// thinking you're all cool and great.
val itemsEach = if (recipients.isEmpty) 1 else Math.max(1, items.size / recipients.size)
val remainder = if (items.isEmpty) 0 else items.size % itemsEach
val iterator = items.toList.iterator
recipients.zipWithIndex.map { case (recipient, i) =>
val count = if (i < remainder) itemsEach + 1 else itemsEach
(recipient, iterator.take(count).toList)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment