There is certain type of iteration that I ofent do in lisp and find myself wishing to do in Scala. Perhaps it is not very idiomatic in Scala.
(let ((my-list '(a b c d e f)))
(mapcon (lambda (is)
(when (cdr is)
(let ((i1 (car is)))
(mapcar (lambda (i2)
(list i1 i2))
(cdr is)))))
my-list))
Which evaluates to the following:
((A B) (A C) (A D) (A E) (A F)
(B C) (B D) (B E) (B F)
(C D) (C E) (C F)
(D E) (D F)
(E F))
I.e. it iterates i1
and i2
over the given list but only for i2
strictly to the right of i1
. Thus by construction we have (c d)
in the return list, but not (d c)
.
I can’t see how this could be implemented in Scala for general collections. To be implemented efficiently the collection needs to be (1) ordered, (2) list-like in the sense that head
and tail
are easy to compute [not an array or set], and (3) at multiply iterable [not iterable only once].
Perhaps this works ONLY for List
, not sure if there is a larger set of types for which it makes sense.
Here is my implementation this lisp idiom in Scala.
I wonder whether someone can comment on this implementation. Is it the correct
way to perform this iteration? I believe, (and it’s hidden from the programmer by the for
abstrction), that the lists are converted to iterators, and I have to convert the final iterator back to a List
at the end.
It seems like there should be a better way without resorting to this conversion, i.e. by manipulating the cons cells directly. On the other hand, the Scala code is indeed very concise and readable.
val data = List("a","b","c","d","e")
val tmp = for {
is <- data.tails
if is.nonEmpty
i1 = is.head
i2 <- is.tail
} yield (i1,i2)
tmp.toList
Which evaluates to the following:
List((a,b), (a,c), (a,d), (a,e), (b,c), (b,d), (b,e), (c,d), (c,e), (d,e))