如何遍历SparseArray?

时间:2011-11-03 17:24:26

标签: java android

有没有办法迭代Java SparseArray(适用于Android)?我使用sparsearray轻松地按索引获取值。我找不到一个。

9 个答案:

答案 0 :(得分:506)

似乎我找到了解决方案。我没有正确地注意到keyAt(index)函数。

所以我会选择这样的东西:

for(int i = 0; i < sparseArray.size(); i++) {
   int key = sparseArray.keyAt(i);
   // get the object by the key.
   Object obj = sparseArray.get(key);
}

答案 1 :(得分:174)

如果你不关心密钥,那么valueAt(int)可以在迭代稀疏数组时直接访问这些值。

for(int i = 0, nsize = sparseArray.size(); i < nsize; i++) {
    Object obj = sparseArray.valueAt(i);
}

答案 2 :(得分:16)

你可以创建自己的ListIterator:

public final class SparseArrayIterator<E> implements ListIterator<E> {

private final SparseArray<E> array;
private int cursor;
private boolean cursorNowhere;

/**
 * @param array
 *            to iterate over.
 * @return A ListIterator on the elements of the SparseArray. The elements
 *         are iterated in the same order as they occur in the SparseArray.
 *         {@link #nextIndex()} and {@link #previousIndex()} return a
 *         SparseArray key, not an index! To get the index, call
 *         {@link android.util.SparseArray#indexOfKey(int)}.
 */
public static <E> ListIterator<E> iterate(SparseArray<E> array) {
    return iterateAt(array, -1);
}

/**
 * @param array
 *            to iterate over.
 * @param key
 *            to start the iteration at. {@link android.util.SparseArray#indexOfKey(int)}
 *            < 0 results in the same call as {@link #iterate(android.util.SparseArray)}.
 * @return A ListIterator on the elements of the SparseArray. The elements
 *         are iterated in the same order as they occur in the SparseArray.
 *         {@link #nextIndex()} and {@link #previousIndex()} return a
 *         SparseArray key, not an index! To get the index, call
 *         {@link android.util.SparseArray#indexOfKey(int)}.
 */
public static <E> ListIterator<E> iterateAtKey(SparseArray<E> array, int key) {
    return iterateAt(array, array.indexOfKey(key));
}

/**
 * @param array
 *            to iterate over.
 * @param location
 *            to start the iteration at. Value < 0 results in the same call
 *            as {@link #iterate(android.util.SparseArray)}. Value >
 *            {@link android.util.SparseArray#size()} set to that size.
 * @return A ListIterator on the elements of the SparseArray. The elements
 *         are iterated in the same order as they occur in the SparseArray.
 *         {@link #nextIndex()} and {@link #previousIndex()} return a
 *         SparseArray key, not an index! To get the index, call
 *         {@link android.util.SparseArray#indexOfKey(int)}.
 */
public static <E> ListIterator<E> iterateAt(SparseArray<E> array, int location) {
    return new SparseArrayIterator<E>(array, location);
}

private SparseArrayIterator(SparseArray<E> array, int location) {
    this.array = array;
    if (location < 0) {
        cursor = -1;
        cursorNowhere = true;
    } else if (location < array.size()) {
        cursor = location;
        cursorNowhere = false;
    } else {
        cursor = array.size() - 1;
        cursorNowhere = true;
    }
}

@Override
public boolean hasNext() {
    return cursor < array.size() - 1;
}

@Override
public boolean hasPrevious() {
    return cursorNowhere && cursor >= 0 || cursor > 0;
}

@Override
public int nextIndex() {
    if (hasNext()) {
        return array.keyAt(cursor + 1);
    } else {
        throw new NoSuchElementException();
    }
}

@Override
public int previousIndex() {
    if (hasPrevious()) {
        if (cursorNowhere) {
            return array.keyAt(cursor);
        } else {
            return array.keyAt(cursor - 1);
        }
    } else {
        throw new NoSuchElementException();
    }
}

@Override
public E next() {
    if (hasNext()) {
        if (cursorNowhere) {
            cursorNowhere = false;
        }
        cursor++;
        return array.valueAt(cursor);
    } else {
        throw new NoSuchElementException();
    }
}

@Override
public E previous() {
    if (hasPrevious()) {
        if (cursorNowhere) {
            cursorNowhere = false;
        } else {
            cursor--;
        }
        return array.valueAt(cursor);
    } else {
        throw new NoSuchElementException();
    }
}

@Override
public void add(E object) {
    throw new UnsupportedOperationException();
}

@Override
public void remove() {
    if (!cursorNowhere) {
        array.remove(array.keyAt(cursor));
        cursorNowhere = true;
        cursor--;
    } else {
        throw new IllegalStateException();
    }
}

@Override
public void set(E object) {
    if (!cursorNowhere) {
        array.setValueAt(cursor, object);
    } else {
        throw new IllegalStateException();
    }
}
}

答案 3 :(得分:8)

对于使用Kotlin的人,老实说,迭代SparseArray的最简单方法是:使用AnkoAndroid KTX中的Kotlin扩展名! (感谢Yazazzello指出Android KTX)

只需致电forEach { i, item -> }

答案 4 :(得分:7)

使用上述循环引线将SparseArray中的所有元素移至Exception

要避免这种情况请按照以下代码使用普通循环从SparseArray删除所有元素

private void getValues(){      
    for(int i=0; i<sparseArray.size(); i++){
          int key = sparseArray.keyAt(i);
          Log.d("Element at "+key, " is "+sparseArray.get(key));
          sparseArray.remove(key);
          i=-1;
    }
}

答案 5 :(得分:5)

以下是Iterable<T>的简单SparseArray<T>public class SparseArrayIterator<T> implements Iterator<T> { private final SparseArray<T> array; private int index; public SparseArrayIterator(SparseArray<T> array) { this.array = array; } @Override public boolean hasNext() { return array.size() > index; } @Override public T next() { return array.valueAt(index++); } @Override public void remove() { array.removeAt(index); } } public class SparseArrayIterable<T> implements Iterable<T> { private final SparseArray<T> sparseArray; public SparseArrayIterable(SparseArray<T> sparseArray) { this.sparseArray = sparseArray; } @Override public Iterator<T> iterator() { return new SparseArrayIterator<>(sparseArray); } } 实施:

public class SparseKeyValue<T> {
    private final int key;
    private final T value;

    public SparseKeyValue(int key, T value) {
        this.key = key;
        this.value = value;
    }

    public int getKey() {
        return key;
    }

    public T getValue() {
        return value;
    }
}

public class SparseArrayKeyValueIterator<T> implements Iterator<SparseKeyValue<T>> {
    private final SparseArray<T> array;
    private int index;

    public SparseArrayKeyValueIterator(SparseArray<T> array) {
        this.array = array;
    }

    @Override
    public boolean hasNext() {
        return array.size() > index;
    }

    @Override
    public SparseKeyValue<T> next() {
        SparseKeyValue<T> keyValue = new SparseKeyValue<>(array.keyAt(index), array.valueAt(index));
        index++;
        return keyValue;
    }

    @Override
    public void remove() {
        array.removeAt(index);
    }

}

public class SparseArrayKeyValueIterable<T> implements Iterable<SparseKeyValue<T>> {
    private final SparseArray<T> sparseArray;

    public SparseArrayKeyValueIterable(SparseArray<T> sparseArray) {
        this.sparseArray = sparseArray;
    }

    @Override
    public Iterator<SparseKeyValue<T>> iterator() {
        return new SparseArrayKeyValueIterator<T>(sparseArray);
    }
}

如果您不仅要迭代值而且要迭代密钥:

Iterable<T>

创建返回Iterable<SparseKeyValue<T>>public abstract class SparseArrayUtils { public static <T> Iterable<SparseKeyValue<T>> keyValueIterable(SparseArray<T> sparseArray) { return new SparseArrayKeyValueIterable<>(sparseArray); } public static <T> Iterable<T> iterable(SparseArray<T> sparseArray) { return new SparseArrayIterable<>(sparseArray); } } 的实用程序方法很有用:

SparseArray<T>

现在您可以迭代SparseArray<String> a = ...; for (String s: SparseArrayUtils.iterable(a)) { // ... } for (SparseKeyValue<String> s: SparseArrayUtils.keyValueIterable(a)) { // ... }

ValueError: invalid literal for int() with base 10.

答案 6 :(得分:1)

如果您使用Kotlin,则可以使用扩展功能,例如:

fun <T> LongSparseArray<T>.valuesIterator(): Iterator<T> {
    val nSize = this.size()
    return object : Iterator<T> {
        var i = 0
        override fun hasNext(): Boolean = i < nSize
        override fun next(): T = valueAt(i++)
    }
}

fun <T> LongSparseArray<T>.keysIterator(): Iterator<Long> {
    val nSize = this.size()
    return object : Iterator<Long> {
        var i = 0
        override fun hasNext(): Boolean = i < nSize
        override fun next(): Long = keyAt(i++)
    }
}

fun <T> LongSparseArray<T>.entriesIterator(): Iterator<Pair<Long, T>> {
    val nSize = this.size()
    return object : Iterator<Pair<Long, T>> {
        var i = 0
        override fun hasNext(): Boolean = i < nSize
        override fun next() = Pair(keyAt(i), valueAt(i++))
    }
}

如果愿意,您也可以转换为列表。示例:

sparseArray.keysIterator().asSequence().toList()

我认为使用remove本身(而不是迭代器)上的LongSparseArray删除项甚至是安全的,因为它是按升序排列的。


编辑:似乎还有一种更简单的方法,就是使用collection-ktx(例如here)。实际上,它的实现方式与我写的非常相似。

Gradle需要这样做:

implementation 'androidx.core:core-ktx:#'
implementation 'androidx.collection:collection-ktx:#'

这是LongSparseArray的用法:

    val sparse= LongSparseArray<String>()
    for (key in sparse.keyIterator()) {
    }
    for (value in sparse.valueIterator()) {
    }
    sparse.forEach { key, value -> 
    }

答案 7 :(得分:-5)

答案是否定的,因为SparseArray没有提供它。正如pst所说,这件事没有提供任何接口。

您可以从0 - size()循环并跳过返回null的值,但这是关于它的。

正如我在评论中所述,如果您需要迭代使用Map而不是SparseArray。例如,使用按键顺序迭代的TreeMap

TreeMap<Integer, MyType>

答案 8 :(得分:-6)

接受的答案中有一些漏洞。 SparseArray的优点在于它允许空隙中的间隙。所以,我们可以在SparseArray中有两个这样的地图...

(0,true)
(250,true)

请注意,此处的大小为2.如果我们迭代大小,我们将只获取映射到索引0和索引1的值的值。因此不会访问键为250的映射。

for(int i = 0; i < sparseArray.size(); i++) {
   int key = sparseArray.keyAt(i);
   // get the object by the key.
   Object obj = sparseArray.get(key);
}

执行此操作的最佳方法是迭代数据集的大小,然后使用数组上的get()检查这些indeces。这是一个适配器的示例,我允许批量删除项目。

for (int index = 0; index < mAdapter.getItemCount(); index++) {
     if (toDelete.get(index) == true) {
        long idOfItemToDelete = (allItems.get(index).getId());
        mDbManager.markItemForDeletion(idOfItemToDelete);
        }
    }

我认为理想情况下SparseArray系列会有一个getKeys()方法,但是它没有。