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