Scala вставить в список в определенных местах - PullRequest
9 голосов
/ 13 января 2011

Это проблема, которую я решил, однако, будучи абсолютным императивом Scala Noob, я чувствую, что нашел что-то совершенно не элегантное. Любые идеи по улучшению приветствуются.

val l1 = 4 :: 1 :: 2 :: 3 :: 4 :: Nil // original list
val insert = List(88,99) // list I want to insert on certain places

// method that finds all indexes of a particular element in a particular list
def indexesOf(element:Any, inList:List[Any]) = {
        var indexes = List[Int]()
        for(i <- 0 until inList.length) {
                if(inList(i) == element) indexes = indexes :+ i
        }
        indexes
}


var indexes = indexesOf(4, l1) // get indexes where 4 appears in the original list

println(indexes)

var result = List[Any]()

// iterate through indexes and insert in front
for(i <- 0 until indexes.length) {
        var prev = if(i == 0) 0 else indexes(i-1)
        result = result ::: l1.slice(prev, indexes(i)) ::: insert
}
result = result ::: l1.drop(indexes.last) // append the last bit from original list

println(result)

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

var final:List[Any] = (0 /: indexes) {(final, i) => final ::: ins ::: l1.slice(i, indexes(i))

Ответы [ 3 ]

14 голосов
/ 13 января 2011
def insert[A](xs: List[A], extra: List[A])(p: A => Boolean) = {
  xs.map(x => if (p(x)) extra ::: List(x) else List(x)).flatten
}

scala> insert(List(4,1,2,3,4),List(88,99)){_ == 4}
res3: List[Int] = List(88, 99, 4, 1, 2, 3, 88, 99, 4)

Редактировать: объяснение добавлено.

Наша цель - вставить список (называемый extra) перед выбранными элементами в другом списке (здесь называемом xs -обычно используется для списков, как если бы одна вещь была x, тогда многие из них должны быть множественным числом xs).Мы хотим, чтобы это работало с любым типом списка, который у нас может быть, поэтому мы аннотируем его универсальным типом [A].

Какие элементы являются кандидатами для вставки?При написании функции мы не знаем, поэтому мы предоставляем функцию, которая говорит true или false для каждого элемента (p: A => Boolean).

Теперь для каждого элемента в списке x мы проверяем- Должны ли мы сделать вставку (т. е. p(x) верно)?Если да, мы просто создаем его: extra ::: List(x) это просто элементы extra, за которыми следует один элемент x.(Может быть лучше написать это как extra :+ x - добавьте один элемент в конце.) Если нет, у нас есть только один элемент, но мы делаем его List(x) вместо просто x, потому что мы хотим всеиметь тот же тип.Так что теперь, если у нас есть что-то вроде

4 1 2 3 4

и наше условие заключается в том, что мы вставляем 5 6 перед 4, мы генерируем

List(5 6 4) List(1) List(2) List(3) List(5 6 4)

Это именно то, что мы хотим,кроме того, у нас есть список списков.Чтобы избавиться от внутренних списков и объединить все в один список, мы просто вызываем flatten.

10 голосов
/ 13 января 2011

Уловка сглаживания - это мило, я бы даже не подумал использовать здесь map.С моей точки зрения, эта проблема является типичным приложением для фолда, так как вы хотите пройтись по списку и что-то «собрать» (список результатов).Поскольку нам не нужен наш список результатов в обратном направлении, foldRight (он же :\) - вот правильная версия:

def insert[A](xs: List[A], extra: List[A])(p: A => Boolean) = 
  xs.foldRight(List[A]())((x,xs) => if (p(x)) extra ::: (x :: xs) else x :: xs)
3 голосов
/ 13 января 2011

Вот еще одна возможность, используя Seq#patch для обработки фактических вставок.Вам нужно сложить Right так, чтобы сначала обрабатывались более поздние индексы (вставки изменяют индексы всех элементов после вставки, иначе было бы сложно)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...