Scala: перебирать каждый символ строки и использовать сопоставление с образцом

Я думаю, то, что я пытаюсь сделать, довольно очевидно. Для каждого символа в строке1 выведите что-нибудь, используя соответствие шаблона. (У меня есть string2, потому что я буду использовать сопоставление с образцом string1, чтобы сделать что-то со строкой 2 и вернуть строку 2)

По какой-то причине мой код выводит только "()".

Также, как мне убедиться, что мой код возвращает строку. Когда я помещаю код в терминал, он говорит: (string1: String)String => Unit, как мне заставить его сказать (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"
    }
  }
}

РЕДАКТИРОВАТЬ:

Я просто хотел бы указать, что я хотел бы сделать с string2:

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

Но это возвращает вектор / список строк. Я хочу, чтобы все эти случаи работали на одном и том же объекте string2. Так что, если я тестирую метод на "привет", он должен вернуть "OLLEH".

Спасибо

4 ответа

Решение

Если вы вставите свое определение в REPL Scala, вы увидите, что тип функции, которую вы определили,

stringPipeline: (string1: String)String => Unit

то есть функция, которая принимает строку string1 в качестве ввода и возвращает замыкание, принимая в качестве ввода вторую строку string2 и возвращая Unitэто как void в Java и имеет только значение (),

Так почему возвращаемое закрытие имеет Unit как тип возвращаемого значения? Его тело содержит только одно выражение:

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

for оценивает его внутреннее выражение

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

для каждого возможного c в string1 а затем возвращается (), Другими словами, for не позволяя значениям, произведенным в нем, пройти.

Если вы хотите напечатать строки "Upper Case", вам нужно написать

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

Тогда возвращаемое значение замыкания все равно будет (), но его оценка выведет строки в match выражение как побочный эффект.

Кстати, почему вы ввели параметр string2, если не используете его?

РЕДАКТИРОВАТЬ

Поскольку выходные данные функции внутри цикла используются как входные данные для следующего цикла цикла, вам нужна функция сгиба, т.е. что-то вроде этого:

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

Вы забыли yield после for ( ... )следовательно, последний for просто бежит, выбрасывает все внутри тела и, наконец, возвращает юнит (),

Если вы хотите что-то вернуть, вы должны использовать что-то вроде этого:

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

Это даст вам своего рода "список описаний действий" для каждого string2,

Если вы действительно хотите print что-то сразу, вы можете сделать это:

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

но так, как сейчас, он не возвращает ничего значимого и не имеет побочных эффектов.

РЕДАКТИРОВАТЬ:

Обновление: если вы хотите лечить string1 как последовательность операций и string2 в качестве "материала", к которому вы хотите применить эти операции, вы можете сделать что-то вроде этого:

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

Вышесказанное делает следующее: оно начинается с string2, а затем применяет каждую операцию из string1 результат всех преобразований, накопленных до сих пор.

Если ваша цель - получить функцию, которая выполняет шаблон для строки, вы можете сделать что-то вроде этого:

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

Эта функция возвращает рекурсивную функцию, которая выполняет одну букву шаблона друг за другом и, наконец, возвращает результат String.

Затем вы можете сделать что-то вроде этого:

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

который возвращается OLLEH

Однако это не итеративный, а рекурсивный подход (который лучше подходит для функционального языка программирования, такого как Scala).

Вы должны реализовать свой конвейер таким образом, чтобы он складывался поверх символов ops строка с каждым символом, являющимся стадией преобразования в конвейере.

Вы начинаете с input строка для первого сгиба, а затем каждый последующий сгиб ops Строка преобразует вывод последнего сгиба.

Теперь вам просто нужно добавить различные операции преобразования, когда вы сталкиваетесь с разными персонажами при сворачивании ops строка.

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
Другие вопросы по тегам