Как я могу взять разные куски из последовательности Kotlin? - PullRequest
0 голосов
/ 13 июня 2019

Если у меня есть последовательность Kotlin, каждый вызов take(n) перезапускает последовательность.

val items = generateSequence(0) {
    if (it > 9) null else it + 1
}

@Test fun `take doesn't remember position`() {
    assertEquals(listOf(0, 1), items.take(2).toList())
    assertEquals(listOf(0, 1, 2), items.take(3).toList())
}

Есть ли простой способ написать, скажем, another(n) такой, что

@Test fun `another does remember position`() {
    assertEquals(listOf(0, 1), items.another(2).toList())
    assertEquals(listOf(2, 3, 4), items.another(3).toList())
}

Полагаю, мне нужно что-то, что не Sequence, чтобы сохранить состояние, поэтому, возможно, то, что я на самом деле прошу, это хорошее определение fun Iterator<T>.another(count: Int): List<T>

Ответы [ 4 ]

2 голосов
/ 13 июня 2019

Sequence не запоминает свою позицию, но iterator запоминает:

val iterator : Iterator<Int> = items.iterator()

Теперь все, что вам нужно, это что-то вроде take(n), но для Iterator<T>:

public fun <T> Iterator<T>.another(n: Int): List<T> {
    require(n >= 0) { "Requested element count $n is less than zero." }
    if (n == 0) return emptyList()
    var count = 0
    val list = ArrayList<T>(n)
    for (item in this) {
        list.add(item)
        if (++count == n)
            break
    }
    return list
}
1 голос
/ 13 июня 2019

Чтобы ответить на последнюю часть вашего вопроса:

Я полагаю, что мне нужно что-то, что не является Последовательностью, чтобы сохранить состояние, поэтому, возможно, то, что я на самом деле прошу, этохорошее определение забавного Iterator.another (count: Int): List

Одной из таких реализаций будет:

fun <T> Iterator<T>.another(count: Int): List<T> {
    val collectingList = mutableListOf<T>()
    while (hasNext() && collectingList.size < count) {
        collectingList.add(next())
    }
    return collectingList.toList()
}

. Этот тест проходит успешно, если вы используете итератор, созданныйпоследовательность:

@Test
fun `another does remember position`() {
    val items = generateSequence(0) {
        if (it > 9) null else it + 1
    }.iterator() //Use the iterator of this sequence.
    assertEquals(listOf(0, 1), items.another(2))
    assertEquals(listOf(2, 3, 4), items.another(3))
}

Для меня то, что вы описали, является итератором, поскольку это то, что позволяет вам просматривать коллекцию или последовательность и т. д., но также запоминать последнюю позицию.

NB. Реализация выше не была написана, чтобы учесть, что должно происходить для неположительных подсчетов, и если число больше, чем осталось для перебора, вам будет возвращен список, который имеет меньший размер, чем n.Я полагаю, вы могли бы считать это упражнение для себя: -)

1 голос
/ 13 июня 2019

Что по этому поводу:

    @Test
    fun `another does remember position`() {
        val items: Sequence<Int> = generateSequence(0) {
            if (it > 9) null else it + 1
        }

        val (first, rest) = items.another(2)
        assertEquals(listOf(0, 1), first.toList())
        assertEquals(listOf(2, 3, 4), rest.another(3).first.toList())
    }

    fun <T> Sequence<T>.another(n: Int): Pair<Sequence<T>, Sequence<T>> {
        return this.take(n) to this.drop(n)
    }
0 голосов
/ 13 июня 2019

Sequence не запоминает свою позицию, но iterator запоминает:

val iterator : Iterator<Int> = items.iterator()

К сожалению, для итератора нет take(n), поэтому для использования одного из stdlib вам нужноОберните iter в Iterable:

val iterable : Iterable<Int> = items.iterator().asIterable()

fun <T> Iterator<T>.asIterable() : Iterable<T> = object : Iterable<T> {
    private val iter = this@asIterable
    override fun iterator() = iter
}

Это заставит itareble.take(n) запомнить его положение, но, к сожалению, есть ошибка «один за другим», потому что стандарт .take(n) также запрашивает один элементмногие:

public fun <T> Iterable<T>.take(n: Int): List<T> {
    require(n >= 0) { "Requested element count $n is less than zero." }
    if (n == 0) return emptyList()
    if (this is Collection<T>) {
        if (n >= size) return toList()
        if (n == 1) return listOf(first())
    }
    var count = 0
    val list = ArrayList<T>(n)
    for (item in this) {
        if (count++ == n)
            break
        list.add(item)
    }
    return list.optimizeReadOnlyList()
}

Это можно исправить с помощью небольшого изменения:

public fun <T> Iterable<T>.take2(n: Int): List<T> {
    require(n >= 0) { "Requested element count $n is less than zero." }
    if (n == 0) return emptyList()
    if (this is Collection<T>) {
        if (n >= size) return toList()
        if (n == 1) return listOf(first())
    }
    var count = 0
    val list = ArrayList<T>(n)
    for (item in this) {


        list.add(item)
        //count++
        if (++count == n)
            break
    }
    return list
}

Теперь оба теста пройдены:

@Test fun `take does not remember position`() {
    assertEquals(listOf(0, 1), items.take2(2).toList())
    assertEquals(listOf(0, 1, 2), items.take2(3).toList())
}

@Test fun `another does remember position`() {
    assertEquals(listOf(0, 1), iter.take2(2).toList())
    assertEquals(listOf(2, 3, 4), iter.take2(3).toList())
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...