0

我试图用 Stream 替换我的 while 循环,但是当我使用 Stream 版本时,最后一个元素总是丢失。我想我明白为什么它丢失了,但我不知道如何解决这个问题。有什么建议吗?还有更好的方法吗?谢谢

使用流:

if(cursor.moveToFirst) {
val result = Stream.continually((
  Song(
    cursor.getLong(c(BaseColumns._ID)),
    cursor.getString(c(MediaColumns.TITLE))     
  ),
  cursor.moveToNext))
.takeWhile(_._2)
.map(_._1)
result.toList
}

这是while循环版本工作正常。

cursor.moveToFirst()
var i = 0
var list: List[Song] = List.empty
while (i < cursor.getCount()) {
  val s = Song(
    cursor.getLong(c(BaseColumns._ID)),
    cursor.getString(c(MediaColumns.TITLE)))
  i = i + 1
  list = list :+ s
  cursor.moveToNext()

笔记:

移动到下一个

将光标移动到下一行。如果光标已经超过结果集中的最后一个条目,则此方法将返回 false。

4

2 回答 2

2

假设您有一个条目。你产生元组

(song, false)

扔掉。这显然不好。即使那里没有另一首歌,您也想保留这首歌!因此,您可以尝试一个选项——如果有歌曲则加载,如果没有则不加载。您还必须以不同方式处理第一个元素,因为moveToFirst它与moveToNext. 像这样:

def loadSong = Song(
  cursor.getLong(c(BaseColumns._ID)),
  cursor.getString(c(MediaColumns.TITLE))     
)

if (cursor.moveToFirst) {
  val songs = Stream(Some(loadSong)) ++
    Stream.continually(if (cursor.moveToNext()) Some(loadSong) else None)
  songs.flatten.toList
}

请注意,您实际上并没有在这里使用流的流畅性,因此您也可以使用Iterator.continually.

注意:我可能会改为将包装逻辑移动到someLong并产生类似的东西:

def loadSong(b: Boolean) = if (!b) None else Some(Song(
  cursor.getLong(c(BaseColumns._ID)),
  cursor.getString(c(MediaColumns.TITLE))     
))

val songs = Stream(loadSong(cursor.moveToFirst())) ++
    Stream.continually(loadSong(cursor.moveToNext())
songs.flatten.toList

或者,考虑到我个人图书馆中的方法:

def optIn[A](b: Boolean)(a: => A) = if (b) Some(a) else None

以前的普通 loadSong 与

val songs = Stream(optIn(cursor.moveToFirst)(loadSong)) ++
  Stream.continually(optIn(cursor.moveToNext)(loadSong))
songs.flatten.toList

可能是最紧凑和可读的。(一旦你知道如何阅读optIn。)

于 2013-07-21T15:37:16.453 回答
1

您的光标是一种迭代器,只是不太方便。因此,作为 Rex Kerr 答案的替代方案,您可以抽象出您cursorIterator(or Stream) 之间的整个转换,以便您可以像这样遍历光标:

def loadSong(c: Cursor) = (
  c.getLong(c(BaseColumns._ID)),
  c.getString(c(MediaColumns.TITLE))     
)

cursor.map(loadSong).toList

为此,您只需要在每次迭代时从您CursorIterator[Cursor]位置隐式转换到光标处于正确状态(准备好从中读取)的位置。一个实现可以是:

implicit def cursor2Iterator(c: Cursor): Iterator[Cursor] = if (c.moveToFirst) 
  new NonEmptyCursorIterator(c) else Iterator.empty

sealed class NonEmptyCursorIterator(private val c: Cursor) extends Iterator[Cursor] {
    private[this] var hasNext0 = true // always has at least one element

    def hasNext() = {
      if (!hasNext0) hasNext0 = c.moveToNext
      hasNext0
    }

    def next(): Cursor = if (hasNext()) {
      hasNext0 = false 
      c
    } else throw new NoSuchElementException("hasNext() is false")
}

这使得代码简短易读。

于 2013-07-21T16:24:39.057 回答