2012-06-23 1 views
27

Так я работаю через несколько упражнений в «Scala для нетерпеливых» и один из них:Char или String -> Значение Unicode в Scala?

Написать for цикл для вычисления произведения кодов Unicode всех букв в строке. Например, произведение символов в «Привет» равно 9415087488 L.

Следующая проблема заключается в том, чтобы сделать то же самое, но без цикла for - это намеки на то, что мы должны проверить StringOps в Scaladoc.

Я проверил раздел RichChar и StringOps в Скаладоке, и, возможно, я неправильно читаю или смотрю не в то место, но я не могу найти ничего, что подталкивает меня к их результату. Я до сих пор пробовал:

scala> x.foldLeft(1)(_ * _.toInt) 
res0: Int = 825152896 

scala> x.foldLeft(1)(_ * _.getNumericValue) 
res5: Int = 2518992 

scala> x.foldLeft(1)(_ * _.intValue()) 
res6: Int = 825152896 

scala> var x = 1 
x: Int = 1 

scala> for (c <- "Hello") x *= c.toInt 

scala> x 
res12: Int = 825152896 

Который не соответствует их выходу.

Как это сделать, как в режиме for, так и в виде for?

Спасибо!

+0

Там еще один способ, если вы делаете это в два этапа. Подсказка: последний из двух методов имеет неявный параметр. –

ответ

26

Когда вы сделаете x.foldLeft(1)(_ * _.toInt), тип результата будет иметь отношение к Int, но 9415087488 является слишком большим для Int, чтобы его сохранить.

Для этого вам необходимо сообщить Scala, используя Long.

scala> val x = "Hello" 
x: java.lang.String = Hello 

scala> x.foldLeft(1L)(_ * _.toInt) 
res1: Long = 9415087488 

scala> var x: Long = 1 
x: Long = 1 

scala> for (c <- "Hello") x *= c.toInt 

scala> x 
res7: Long = 9415087488 
+0

Ahhh получил его. Благодаря! – adelbertc

+5

Спасибо тоже. Как ни странно, в pdf-версии, которую я только что загрузил, указано неправильное значение (825152896). – Markus

+0

странно, но с «for (fi <-« Hello ») i * = fi.toChar« Я имею то же значение, что и в книге. Хммм. –

12

Если вы конвертируете каждый RichChar String .toLong, он также работает. Например, это:

str.map (_.toLong).product - работа в нормально и без foldLeft или циклов

Это циклический вариант:

def product(str: String): Long = { 
    var prod: Long = 1 
    for (ch <- str) prod *= ch 
    prod 
} 
3

Самый простой способ я нашел, чтобы сделать это:

"Hello".foldLeft(1L)((x:Long, y:Char) => x*y) 

Метод принимает два параметра: длинную и функцию делегата, которая принимает длину и символ Char и возвращает Long. Вы можете передать анонимную функцию непосредственно, как это, или вы можете определить функцию в другом месте и передать его, например, так:

def multiply(x:Long, y:Char) = { 
    x*y 
} 
"Hello".foldLeft(1L)(multiply) 
4

Вот еще один способ:

scala> (for (c <- "Hello") yield c.toLong).product 
res36: Long = 9415087488 
6

Там особый «продукт» метод в StringOps, который умножает элементы коллекции. Но он использует Char, потому что строка состоит из элементов char. И у нас переполнение при попытке вычислить «Hello» .product. Таким образом, я преобразовал строку в вектор значений Long Unicode на «Привет» .map (_ toLong.) И вычислил произведение его элементов с помощью этого кода:

scala> "Hello".map(_.toLong).product 
res79: Long = 9415087488 
+0

Спасибо! Я тоже подозревал переполнение. Но было неуверенно, как попросить его отобразить его в «Лонг». – asgs

+0

Цикл for в ответе Рихада и карта в этом ответе - это нотные варианты. Я считаю, компилятор преобразует цикл for в карту. Это вопрос вкуса, который вы используете. – airfoyle

2

Я думаю, что переход к промежуточной карте является неэффективен, потому что в этом случае коллекция повторяется дважды: один раз для создания карты длин и второй раз для умножения всех элементов. Ненужная временная коллекция Long's также не нужна.Я отдаю свой голос в

"Hello".foldLeft(1L)(_ * _) 
0

Другой вариант: "Hello".aggregate(1L)({(prod,ch) => prod * ch.toLong}, {(p1,p2)=>p1*p2})

Смежные вопросы