Swift List Product - swift

Given two lists in Swift:
let rows = ["a", "b", "c"]
let cols = ["1", "2", "3"]
Is it possible to combine them using list comprehension to produce the following:
squares = ["a1", "a2", "a3", "b1", "b2", "b3", "c1", "c2", "c3"]
Obviously, it can be done using a "for loop" and similar constructs, but I'm specifically for a list comprehension based solution. I know Swift can do some list comprehension (e.g. let evens = Array(filter(1..<10) { $0 % 2 == 0 }) ) but can't figure out if it can do something similar to the following piece of Haskell:
let squares = [ r ++ c | r <- rows, c <- cols]

A possible solution (now updated for Swift 2):
let rows = ["a", "b", "c"]
let cols = ["1", "2", "3"]
let squares = rows.flatMap {
row in
cols.map {
col in
row + col
}
}
print(squares)
// [a1, a2, a3, b1, b2, b3, c1, c2, c3]
The inner map() maps the cols array to an array with the
row number prepended to each entry. The outer flatMap() maps
the rows array to an array of arrays (one for each row) and flattens the result.
Slightly more general, one could define the "product" of two
sequences as an array of tuples (pairs) with all combinations:
func product<S : SequenceType, T : SequenceType>(lseq : S, _ rseq : T) -> [(S.Generator.Element, T.Generator.Element)] {
return lseq.flatMap { left in
rseq.map { right in
(left, right)
}
}
}
and then use it as
let squares = product(rows, cols).map(+)

Related

get indexes of elements containig some value and the coresponding elements from another list

The queston is a mouthful, but the idea pretty simple.
I have 3 lists and a string.
val a = List("x", "y", "z")
val b = List("a1", "a2", "b1", "b2", "c1", "c2", "d1", "d2")
val c = List("1", "1", "2", "2", "3", "3", "4", "4")
val d = "xc1b1"
I need to check if d contains elements from a. If it does I check the position of all the elemtns from b that are present in d and return a set of elements from c that corespond these positions.
The result for the given example is
Set("3", "2")
But when I try
if(a.exists(d.contains)) c(b.indexWhere(d.contains))
I only get
Any = 2
Which corespond to the first encountered elemnt from b ie b1
How would I get the set?
-
if(a.exists(d.contains)) b.zip(c).collect{
case (x, y) if d.contains(x) => y
}
// res1: Any = List(2, 3)
If you need a Set:
if(a.exists(d.contains)) b.zip(c).collect{
case (x, y) if d.contains(x) => y
}.toSet
// res2: Any = Set(2, 3)
I think I've understood what you need to do here, although the question could do with some clarification.
These are the two ways of getting to your set that I found:
if(a.exists(d.contains)) b.collect {
case x if d.contains(x) => c(b.indexOf(x))
}.toSet
if(a.exists(d.contains)) b.filter(d.contains).map(b.indexOf).map(c).toSet
Both find elements of b that are in d, then find their index in b and find their relative elements in c. The first way is more explicit in what it's doing, while the second way is more concise.

Find the sum of a list in Scala

If I have a list of strings and I know the numeric vlaue of each string in the list how do i get the sum of the list?
Example:
I know:
a = 1
b = 2
c = 3
d = 4
e = 5
I am given the following list:
List("a","b","d")
what the best way of calculating the sum 7?
Thanks
val a = Map("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 4, "e" -> 5)
val b = List("a", "b", "d")
b.map(a.getOrElse(_, 0)).sum
If you know that the values are the same as the element position, then you can avoid a map:
object test {
val list = List("a", "b", "c", "d", "e")
def sumThem = (for((letter, value) <- list.zipWithIndex) yield(value + 1)).sum
}
scala> test.sumThem
res2: Int = 15
If you're 100% sure it's only letters
List("a","b","d").foldLeft(0)(_ + _.hashCode - 96)
if not, you can map it before
val letters = (1 to 26).map(x => Character.toString((x+96).toChar) -> x).toMap
and use #sheunis's answer:
val input = List("a","b","d")
input.map(letters.getOrElse(_, 0)).sum

IndexedSeq and removing multiple elements

I have mySeq: IndexedSeq[A] and another myIncludedSeq: IndexedSeq[A], where every element of myIncludedSeq, is contained in mySeq.
I want to create a new IndexedSeq[A] from mySeq without all elements from myIncludedSeq.
I can't find any nice functional approach for this problem. How would you approach it?
Example:
val mySeq = IndexedSeq("a", "b", "a", "c", "d", "a")
val myIncludedSeq = IndexedSeq("a", "d", "a")
//magic
val expectedResult = IndexedSeq("b", "c", "a") //the order does not matter
How about this?
val original = IndexedSeq("a", "b", "a", "c", "d", "a")
val exclude = IndexedSeq("a", "d", "a")
val result = original.diff(exclude)
// IndexedSeq[String] = Vector(b, c, a)
From list's diff doc:
Computes the multiset difference between this list and another sequence.
Returns a new list which contains all elements of this list except
some of occurrences of elements that also appear in "excluding" list. If an
element value x appears n times in that, then the first n occurrences
of x will not form part of the result, but any following occurrences
will.

Can I yield or map one element into many in Scala?

val inArray = Array("a", "b", "c", "d")
// ...
val outArray = Array("a1", "a2", "a3", "b1", "b2", "b3", "c1", "c2", "c3", "d1", "d2", "d3")
How to map inArray to outArray?
The idea is to iterate through inArray yielding 3 elements (by concatenating an index in this example) from each of its elements.
You can do that with flatMap.
inArray.flatMap(c => (1 to 3).map(c+))
This can look better using a for-comprehension
for {
s <- inArray
i <- Array(1, 2, 3) //or other traversable
}
yield s + i
This uses a combination of map and flatMap under the covers as described in detail in the SLS
Using for-comprehension.
scala> for {
| x <- Array("a", "b", "c", "d")
| n <- 1 to 3
| } yield x + n
res0: Array[java.lang.String] = Array(a1, a2, a3, b1, b2, b3, c1, c2, c3, d1, d2, d3)

Proper way for looping in Scala

Suppose I have an array of strings in Scala:
val strings = Array[String]("1", "2", "3", "4", "5", "6", "7")
What I need is to make a new array which elements will be obtained as a concatenation of each three (any number) consequent elements of the first array, which should result in ("123", "456", "7")
Being new to Scala I wrote the following code which was neither concise nor effective:
var step = 3
val strings = Array[String]("1", "2", "3", "4", "5", "6", "7")
val newStrings = collection.mutable.ArrayBuffer.empty[String]
for (i <- 0 until strings.length by step) {
var elem = ""
for (k <- 0 until step if i + k < strings.length) {
elem += strings(i + k)
}
newStrings += elem
}
What would be the Scala way for doing this?
strings.grouped(3).map(_.mkString).toArray
or
strings grouped 3 map (_.mkString) toArray
I personally prefer the first version :)
strings grouped 3 map (_.mkString)
or (in order to really get an Array back)
(strings grouped 3 map (_.mkString)).toArray
... or use sliding
val strings = Array[String]("1", "2", "3", "4", "5", "6", "7")
strings.sliding (3, 3) .map (_.mkString).toArray
res19: Array[String] = Array(123, 456, 7)
Sliding: You take 3, and move forward 3. Variants:
scala> strings.sliding (3, 2) .map (_.mkString).toArray
res20: Array[String] = Array(123, 345, 567)
take 3, but forward 2
scala> strings.sliding (2, 3) .map (_.mkString).toArray
res21: Array[String] = Array(12, 45, 7)
take 2, forward 3 (thereby skipping every third)