Reputation: 47
How can I reduce a collection via adjacent pairs?
For instance, let + be a non-associative operator:
(1, 2, 3, 4, 5, 6) => ((1+2) + (3+4)) + (5+6)
(a, b, c, d, e, f, g, h) => ((a+b) + (c+d)) + ((e+f) + (g+h))
This question is similar to this, however I don't think parallel collections apply because the semantics require an associative operator for determinism. I'm not concerned so much about parallel execution as I am about the actually associating such that it constructs a balanced expression tree.
Upvotes: 2
Views: 180
Reputation: 44918
Here is a version that does what you want, but treats the "remaining" elements somewhat arbitrarily (if the number of inputs in current iteration is odd, one element is left as-is):
def nonassocPairwiseReduce[A](xs: List[A], op: (A, A) => A): A = {
xs match {
case Nil => throw new IllegalArgumentException
case List(singleElem) => singleElem
case sthElse => {
val grouped = sthElse.grouped(2).toList
val pairwiseOpd = for (g <- grouped) yield {
g match {
case List(a, b) => op(a, b)
case List(x) => x
}
}
nonassocPairwiseReduce(pairwiseOpd, op)
}
}
}
For example, if this is your non-associative operation on String
s:
def putInParentheses(a: String, b: String) = s"(${a} + ${b})"
then your examples
for {
example <- List(
('1' to '6').toList.map(_.toString),
('a' to 'h').toList.map(_.toString)
)
} {
println(nonassocPairwiseReduce(example, putInParentheses))
}
are mapped to
(((1 + 2) + (3 + 4)) + (5 + 6))
(((a + b) + (c + d)) + ((e + f) + (g + h)))
Would be interesting to know why you want to do this.
Upvotes: 2