#scala
#scala
Вопрос:
У меня есть список с некоторыми строками, и я хотел бы объединить / конкатенировать строки, только если длина символов в строках равна <= определенному пределу.
Например, у нас есть список строк:
val xs = List("This is a sentence in index0.", "This is a short sentence.", "This is a very very very loooooooooong sentence.", "This is another short sentence.", "Another one.", "The end!")
Предел объединения равен 60, это означает, что мы должны посмотреть на длины символов в строке, прежде чем объединять ее со следующей строкой и гарантировать, что длина символа не превышает 60. если результат слияния превысит 60, вы не объединяете, а просто берете элемент / строку как есть, переходите к следующему элементу и пытаетесь объединить со следующим.
Итак, если мы возьмем наш приведенный выше список,
мы можем проверить длину символа в каждой строке с помощью:
xs.map(_.length)
res: List[Int] = List(29, 25, 48, 31, 12, 8)
Исходя из этого, мы можем объединить только строки с индексом 0 и 1, оставить индекс 2 как есть и объединить строки с индексом 3, 4 и 5.
Результирующий список строк теперь должен выглядеть следующим образом:
val result = List("This is a sentence in index0.This is a short sentence.", "This is a very very very loooooooooong sentence.", "This is another short sentence.Another one.The end!")
Какой хороший способ реализовать это, предполагая, что вы не знаете, сколько строк будет в списке.
Ответ №1:
Я взломал этот фрагмент кода:
val xs = List(
"This is a sentence in index0.",
"This is a short sentence.",
"This is a very very very loooooooooong sentence.",
"This is another short sentence.",
"Another one.",
"The end!")
println(concatLimited(xs, 60))
def concatLimited(list: List[String], limit: Int): List[String] = {
def concat(left: List[String], middle: String, right: List[String]): List[String] = {
if (right.isEmpty) {
left : middle
}
else {
if (middle.length right.head.length < limit) {
concat(left, middle right.head, right.tail)
}
else {
concat(left : middle, right.head, right.tail)
}
}
}
if (list.isEmpty) List()
else concat(List(), list.head, list.tail)
}
Он использует рекурсивную функцию, которая удаляет элементы из заголовка списка (здесь: right
) и собирает их в параметре middle
до тех пор, пока он не превысит ваш размер, затем он добавляется middle
к результирующему списку left
и начинается с нового middle
, пока right
не станет пустым.
Я надеюсь, что это поможет.
Ответ №2:
Что касается эффективной конкатенации строк, эта реализация concatenate
продолжает находить диапазоны индексов, которые соответствуют критериям ( getNext
сообщает начальный индекс следующего подмножества), и суммирует их с помощью StringBuilder
и, наконец, выдает все объединенные строки.
import scala.annotation.tailrec
import scala.collection.mutable.ListBuffer
object ListConcatenation extends App {
val xs = List(
"This is a sentence in index0.",
"This is a short sentence.",
"This is a very very very loooooooooong sentence.",
"This is another short sentence.",
"Another one.",
"The end!")
concatenate(xs, 60).foreach(println)
def concatenate(values: List[String], limit: Int): List[String] = {
def getNext(start: Int): Int = {
@tailrec
def getNext(sum: Int, index: Int): Int = {
if (index >= values.length)
index
else {
val next = sum values(index).length
if (next > limit)
index
else
getNext(next, index 1)
}
}
getNext(0, start)
}
if (values == null || values.length <= 1)
values
else {
val result = new ListBuffer[String]
var head = 0
do {
val next = getNext(head)
val builder = new StringBuilder
(head until next)
.map(values)
.foreach(builder.append)
result = builder.toString()
head = next
}
while (head < values.length)
result.toList
}
}
}