简体   繁体   中英

Is there a list backed by a Map?

I have 100k items in a list that is displayed in a Swing TreeList. See AutoFilterTreeTableDemo in the jide-demo https://www.jidesoft.com/products/download.htm

When filtering it takes a long time to expand the nodes.

On profiling, Vector.indexOf() was taking ~20 seconds. I switched it to an ArrayList and it took ~5 seconds.

I then cached the List as Map<Row, Integer> where the Integer is the index in the list. This reduced the filtering to ~0.2s.

However, if I add a row somewhere in the middle I have to rebuild the map as the indexes of the list will have changed.

Is there a data structure that uses a map to back the index of the list? Or do I have to manage this by myself?

Alternatively, is there a normal List that has very fast indexOf times? I don't mind sacrificing the insertion/deletion times slightly at the expense of this.

A third option is if there is a more optimal filterable Swing grid that I could use.

EDIT: Code snippet:

    private Map<Row, Integer> rowLookup = new ConcurrentHashMap<Row, Integer>();

    @Override
    public int getRowIndex(Row row) {
        if(rowLookup.isEmpty()) {
            List<Row> existingRows = getRows();
            for(int i = 0; i < existingRows.size(); i++) {
                Row mappingRow = existingRows.get(i);
                rowLookup.put(mappingRow, i);
            }
        }
        if(row == null) {
            return -1;
        } else {
            Integer lineNumber = rowLookup.get(row);
            if(lineNumber == null) {
                lineNumber = -1;
            }
            return lineNumber;
        }
    }

I think you're probably close to the optimal solution as it is. You have two contradictory needs:

  1. You want to be able to randomly insert items
  2. You want to be able to access these items based on a fixed index

Typically for (1) you would use something like either a Map or Linked List

For (2) you would use an Array

The reason (1) conflicts with (2) is that when you do (1) you have to update every subsequent item such that its index is updated. I don't think you'll find a general purpose data structure that does this because it can't be done efficiently.

I think if I were you, apart from restructuring the problem, which I guess isn't possible right now, I would do what you are doing.

However rather than considering the map as being integral, you should use it as a cache.

When you do the lookup, and another check to ensure that the index matches, and if it doesn't clear the entry from the map; find the correct value; then update the Map eg

public int getRowIndex(Row row) {

    Integer index = rowLookup.get(mappingRow);

    List<Row> existingRows = getRows();

    if (index != null) {

        int i = index.intValue();

        if (i < existingRows.size() && row == existingRows.get(i)) {
            return i;
        }

        rowLookup.remove(i);
    }

    /* Otherwise we'll have to look it up the slow way */
    int i = existingRows.indexOf(row);
    rowLookup.put(row, i);
    return i;
}

Sorry haven't tried compiling this it's meant to be illustrative only

You may want to pair this with another function running periodically that rebuilds the cache in its entirety.

Not exactly what you are looking for but it could be considered as an alternative solution to your problem: org.apache.commons.collections.list.TreeList The indexOf method does not outperforms the ArrayList implementation but for your use case I think it'll be acceptable.

This list implementation utilises a tree structure internally to ensure that all insertions and removals are O(log n).

The below table was obtained from their documentation as a measure of their performance in comparison to other List implementations. Downside is it consumes slightly more memory:

 *              get  add  insert  iterate  remove
 * TreeList       3    5       1       2       1
 * ArrayList      1    1      40       1      40
 * LinkedList  5800    1     350       2     325

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM