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))