Reputation: 8443
For a list of string, I do this:
val l = List("a", "r", "e")
l.reduceLeft((x, z) => x + z)
I don't know how to do it for a list of Chars. The following is a compile error:
val chs = List('a', 'r', 'e')
chs.reduceLeft[String]( (x,y) => String.valueOf(x) + String.valueOf(y))
Upvotes: 3
Views: 3935
Reputation: 31
To to show the workings of foldLeft
and foldRight
(and map
, along the way) with a little bit af a "real" operation applied, let's use toChar
(of Int
):
val iA: Int = 65
val cA: Char = iA.toChar //====> A
val cB: Char = 66.toChar //====> B
cA + cB
//====> 131 (Int), since char has no concatenation +, obviously
"" + cA + cB
//====> AB now forced to concatenation + of String
val li: List[Int] = List(65, 66, 67)
li map (i => i.toChar) //====> List(A, B, C)
The parameter of foldLeft
and foldRight
is the "zero element".
I make it explicitly visible here by using "0"
, you want to use ""
for a decent concatenation.
The zero element should generally not be part of the result, but is needed to calculate that result.
In The following code:
i: Int
because of li: List[Int]
acc: String
because of "0"
(accumulator)
+
is String concatenation
li.foldLeft("0")((acc, i) => acc + i.toChar)
//====> 0ABC 0 --> 0A --> 0AB --> 0ABC
li.foldLeft("0")((acc, i) => i.toChar + acc)
//====> CBA0 0 --> A0 --> BA0 --> CBA0
li.foldRight("0")((i, acc) => acc + i.toChar)
//====> 0CBA 0 --> 0C --> 0CB --> 0CBA
li.foldRight("0")((i, acc) => i.toChar + acc)
//====> ABC0 0 --> C0 --> BC0 --> ABC0
Upvotes: 0
Reputation: 44648
If you want to really learn fold
s, you should do something a bit more applicable. While you can of course do this to a string, there are much better ways to create a string from a list of characters. Folds are very powerful and creating a string doesn't quite do it justice
Let's say, for example, you have
case class Employee(fname:String, lname:String, age:Int)
Let's say you also have a HashMap[String, List[Employee]]
that organizes them by position. So you have Joe Shmoe who's a 25 year old Software Engineer, and Larry Larison who's a 37 year old accountant, etc. You can easily use a fold to organize this data into flat structures very simply. If you want to take it and create just a List of the names of your employees you can combine it with a flatMap
to very simply return a List[String]
val employees = Map[String, List[Employee]]("Software Engineer" -> List(new Employee("Joe", "Shmoe", 25), new Employee("Larry", "Larrison", 37)), "Accountant" -> List(new Employee("Harry", "Harrison", 55))).flatMap(_._2).foldLeft[List[String]](Nil)((l,e) => e.fname + " " + e.lname :: l)
employees.flatMap(_._2).foldLeft[List[String]](Nil)(
(li,emp) =>
s"${emp.fname} ${emp.lname}" :: li
)
The flatMap
function gives you a flat list of all Employee
objects. It's passed a Tuple2
of String
and List[Employee]
. The _._2
returns the 2nd item of the Tuple2
which is the list of employees which flatMap
joins together with the others.
From there, you can use foldLeft
on a list of Employee
objects to create a list of their names. Nil
is an empty List
(and will have List[String]
inferred), that's your starting object.
foldLeft
takes a predicate that should use a tuple as it's parameter, the first item of which will be the list formed so far, and the second item of which will be the next item in the list you are iterating over. on the first pass, you'll have an empty list and Joe Shmoe.
In the predicate, you create the string of the Employee
s first and last name and prepend that string to the accumulator, li
.
This returns
List[String] = List(Harry Harrison, Larry Larrison, Joe Shmoe)
Folds are a very useful tool. I've found this page to be very helpful in figuring them out: http://oldfashionedsoftware.com/2009/07/30/lots-and-lots-of-foldleft-examples/
Upvotes: 1
Reputation: 26486
If you just want to accomplish the result:
scala> List('a', 'r', 'e').mkString
res0: String = are
Upvotes: 4
Reputation: 13959
Here's the type signature for reduceLeft
:
def reduceLeft[B >: A](f: (B, A) => B): B
It requires that what you're reducing to be a subtype of the type that you're reducing from so in you're case Char
is A
and String
is B
which is not a subtype of Char
.
You can do a foldLeft which will reduce your list and doesn't require the output to be a subtype of the input:
chs.foldLeft("")((x,y) => x + String.valueOf(y))
Upvotes: 6