Список каждого n-го элемента в данном списке
Это простое упражнение, которое я решаю в Scala: заданный список l
возвращает новый список, содержащий каждый элемент n-th
l
. Если n > l.size
возвращает пустой список.
def skip(l: List[Int], n: Int) =
Range(1, l.size/n + 1).map(i => l.take(i * n).last).toList
Мое решение (см. выше), похоже, работает, но я ищу что-л. проще. Как бы вы его упростили?
Ответы
Ответ 1
scala> def skip[A](l:List[A], n:Int) =
l.zipWithIndex.collect {case (e,i) if ((i+1) % n) == 0 => e} // (i+1) because zipWithIndex is 0-based
skip: [A](l: List[A], n: Int)List[A]
scala> val l = (1 to 10).toList
l: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> skip(l,3)
res2: List[Int] = List(3, 6, 9)
scala> skip(l,11)
res3: List[Int] = List()
Ответ 2
Несколько проще:
scala> val l = (1 to 10).toList
l: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// n == 3
scala> l.drop(2).grouped(3).map(_.head).toList
res0: List[Int] = List(3, 6, 9)
// n > l.length
scala> l.drop(11).grouped(12).map(_.head).toList
res1: List[Int] = List()
(toList просто для того, чтобы заставить iteratot оцениваться)
Работает с бесконечными списками:
Stream.from(1).drop(2).grouped(3).map(_.head).take(4).toList
res2: List[Int] = List(3, 6, 9, 12)
Ответ 3
Более читаемый бит и размер цикла O(l.length/n)
:
def skip(l: List[Int], n: Int) = {
require(n > 0)
for (step <- Range(start = n - 1, end = l.length, step = n))
yield l(step)
}
Ответ 4
Сдвиг влево O(n)
def skip(xs: List[Int], n: Int) = {
xs.foldLeft((List[Int](), n)){ case ((acc, counter), x) =>
if(counter==1)
(x+:acc,n)
else
(acc, counter-1)
}
._1
.reverse
}
scala > skip(List(1,2,3,4,5,6,7,8,9,10), 3)
Tailrec менее читаемый подход O(n)
import scala.annotation.tailrec
def skipTR(xs: List[Int], n: Int) = {
@tailrec
def go(ys: List[Int], acc: List[Int], counter: Int): List[Int] = ys match {
case k::ks=>
if(counter==1)
go(ks, k+:acc , n)
else
go(ks, acc, counter-1)
case Nil => acc
}
go(xs, List(), n).reverse
}
skipTR(List(1,2,3,4,5,6,7,8,9,10), 3)
Ответ 5
Два подхода, основанные на filter
на индексах, следующим образом:
implicit class RichList[A](val list: List[A]) extends AnyVal {
def nthA(n: Int) = n match {
case 0 => List()
case _ => (1 to a.size).filter( _ % n == 0).map { i => list(i-1)}
}
def nthB(n: Int) = n match {
case 0 => List()
case _ => list.zip(Stream.from(1)).filter(_._2 % n == 0).unzip._1
}
}
и так для данного списка
val a = ('a' to 'z').toList
имеем, что
a.nthA(5)
res: List(e, j, o, t, y)
a.nthA(123)
res: List()
a.nthA(0)
res: List()
Обновление
Используя List.tabulate
следующим образом,
implicit class RichList[A](val list: List[A]) extends AnyVal {
def nthC(n: Int) = n match {
case 0 => List()
case n => List.tabulate(list.size) {i =>
if ((i+1) % n == 0) Some(list(i))
else None }.flatten
}
}
Ответ 6
Вы можете опустить toList, если вы не против итератора:
scala> def skip[A](l:List[A], n:Int) =
l.grouped(n).filter(_.length==n).map(_.last).toList
skip: [A](l: List[A], n: Int)List[A]
scala> skip (l,3)
res6: List[Int] = List(3, 6, 9)