1

I think what I'm trying to do is pretty obvious. For every character in a string1, print something using patter matching. (I have string2 there because I will use pattern matching of string1 to do something to string 2 and return String 2)

For some reason my code only prints out "()".

Also how do I make sure that my code returns a String. When I put the code in terminal it says: (string1: String)String => Unit , how do I make it say (string1: String)String => String

def stringPipeline(string1: String) = (string2: String) => {

  for(c <- string1) {
    c match {
      case 'u' => "Upper Case"
      case 'r' => "reverse"
      case _ => "do something"
    }
  }
}

EDIT:

I would just like to point out what I wanted to do with string2:

def stringPipeline(string1: String) = (string2: String) => { 
    for(c <- string1) yield { 
        c match { 
            case 'U' => string2.toUpperCase 
            case 'r' => string2.reverse } } } 

But it's return a vector/list of strings. I want all those cases to work on the same string2 object. So if I test the method on "hello", it should return "OLLEH".

Thanks

Donat
  • 81
  • 3
  • 12
  • Any example of `do something to string2` ? – sarveshseri Feb 05 '18 at 19:38
  • It looks like most of the suggestions I have been given work. But another problem occured. To answer your question, I was trying to do something like: def stringPipeline(string1: String) = (string2: String) => { for(c <- string1) yield { c match { case 'U' => string2.toUpperCase case 'l' => string2.toLowerCase } } } But it's return a vector/list of strings. I want all those cases to work on the same string2 object – Donat Feb 05 '18 at 19:52
  • Now it got less clear than it was before... 1) Can you at least add the types of the expected result? It's not even clear whether you want to return anything or not. 2) For what `string1` do you expect the output "OLLEH" in your example? – Andrey Tyukin Feb 05 '18 at 20:16
  • I want to repeatedly apply each instruction contained in string1 to the string contained in string2, and the return the result? so the out will be a String. so if string1 is "Ur" and string2 is "hello" I will need to capitalize every character in string2 then reverse that String and output "OLLEH" – Donat Feb 05 '18 at 20:22
  • Ah... That's a foldLeft of `string2` with `string1`. – Andrey Tyukin Feb 05 '18 at 20:48

4 Answers4

1

You forgot a yield after the for ( ... ), therefore the last for simply runs, throws away everything inside the body, and finally returns a unit ().

If you want to return something, you should use something like that:

def stringPipeline(string1: String) = (string2: String) => {
  for (c <- string1) yield {
    c match {
      case 'u' => "Upper Case"
      case 'r' => "reverse"
      case _ => "do something"
    }
  }
}

This will give you some sort of "list of action descriptions" for each string2.

If you really want to print something immediately, you can do this:

def stringPipeline(string1: String) = (string2: String) => {
  for (c <- string1) {
    println(c match {
      case 'u' => "Upper Case"
      case 'r' => "reverse"
      case _ => "do something"
    })
  }
}

but the way it is now, it neither returns anything meaningful, nor does it have any side effects.

EDIT:

Update: if you want to treat string1 as a sequence of operations and string2 as the "material" to which you want to apply those operations, you can do something like this:

def stringPipeline(string1: String) = (string2: String) => {
  string1.foldLeft(string2) { 
    case (s, 'u') => s.toUpperCase
    case (s, 'r') => s.reverse
    case (_, x) => 
      throw new Error("undefined string manipulation: " + x)
  }
}

The above does the following: it starts with the string2, and then applies each operation from string1 to the result of all the transformations accumulated so far.

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
0

If your goal is to receive a function, that performs the pattern on a string, you can do something like that:

def stringPipeline(pattern : String) = {
  def handleString(s : String, restPattern : List[Char]) : String = {
     restPattern match{
      case hd :: tl => {
        hd match{
          case 'u' => handleString(s.toUpperCase(), tl)
          case 'r' => handleString(s.reverse, tl)
          case _ => handleString(s, tl)
        }
      }
      case Nil => s    
    }
  }    
  s : String => handleString(s, pattern.toList)
}

This function returns a recursive function, that performs one letter of the pattern after each other, and finally returns the result String.

You can then do something like that:

val s = "urx"
val fun = stringPipeline(s)
println(fun("hello"))

which returns OLLEH

However, it is not an iterative, but a recursive approach (which fits better for a functional programming language like Scala).

Thomas Böhm
  • 1,456
  • 1
  • 15
  • 27
0

If you paste your definition in the Scala REPL you will see that the type of the function you have defined is

stringPipeline: (string1: String)String => Unit

i.e. a function that takes a string string1 as input and returns a closure taking a second string string2 as input, and returning Unit, which is like void in Java and has only the value ().

So why does the returned closure have Unit as return type? Its body contains only one expression:

for(c <- string1) {
    c match {
      case 'u' => "Upper Case"
      case 'r' => "reverse"
      case _ => "do something"
    }
}

for evaluates its internal expression

c match {
    case 'u' => "Upper Case"
    case 'r' => "reverse"
    case _ => "do something"
}

for each possible c in string1 and then returns (). In other words, for is not letting the values produced inside it through.

If you want to print the strings "Upper Case" you need to write

    case 'u' => println("Upper Case")

Then the return value of the closure will still be (), but its evaluation will print the strings in the match expression as a side effect.

On a side note, why did you introduce the parameter string2 if you do not use it?

EDIT

Since the output of the function inside the loop is used as input for the next cycle of the loop, you need a fold function, i.e. something like this:

def stringPipeline(string1: String) = (string2: String) => {
    string1.foldLeft(string2)((s: String, c: Char) =>
        c match {
            case 'u' => s.toUpperCase
            case 'r' => s.reverse
            case _   => s
        }
    )
}
Giorgio
  • 5,023
  • 6
  • 41
  • 71
  • I understand ! not what I was trying to do though. I guess my question is a bit ambiguous and I should have posted what I actually wanted to do with string2. I wanted to do something like: def stringPipeline(string1: String) = (string2: String) => { for(c <- string1) yield { c match { case 'U' => string2.toUpperCase case 'l' => string2.toLowerCase } } } But it's return a vector/list of strings. I want all those cases to work on the same string2 object – Donat Feb 05 '18 at 19:58
  • If I understand correctly, you want to repeatedly apply each instruction contained in `string1` to the string contained in `string2`, and the return the result? – Giorgio Feb 05 '18 at 20:15
  • What would you like to do in this case: case _ => "do something"? What do you mean by "do something"? – Giorgio Feb 05 '18 at 20:21
  • That was kind of dummy code sorry. I replaced "do something" with string2.reverse. Please check my edit on the original post. Thanks – Donat Feb 05 '18 at 20:24
  • 1
    OK, it seems you need a fold. I have updated my answer. – Giorgio Feb 05 '18 at 20:32
0

You need to implement your pipeline such that it folds over the characters of ops string with each character being a stage of transformation in pipeline.

You start with the input string for the first fold and then each subsequent fold of ops string will transform the output of last fold.

Now, you just need to add different transform operations when you encounter different characters while folding the ops string.

def stringPipeline(ops: String) = (input: String) => {
  ops.toLowerCase.foldLeft(input)((str: String, op: Char) => op match {
    case 'u' =>
      println("Operator - 'u' :: Transforming - Upper Case")
      str.toUpperCase
    case 'r' =>
      println("Operator - 'r' :: Transforming - Reverse")
      str.reverse
    case _ =>
      println("Operator - 'unknown' :: Doing Nothing")
      str
  })
}

val pipeline1 = stringPipeline("ur")

val s1 = "abcde"

val s1p1 = pipeline1(s1)

// Operator - 'u' :: Transforming - Upper Case
// Operator - 'r' :: Transforming - Reverse
// s1p1: String = EDCBA
sarveshseri
  • 13,738
  • 28
  • 47