35

Is this possible:

myList = []

myList[12] = 'a'
myList[22] = 'b'
myList[32] = 'c'
myList[42] = 'd'

When I try, I get:

# IndexError: list assignment index out of range # 
2
  • myList = () is actual a tuple, you can't add, remove or find objects in a tuple. Commented May 15, 2009 at 17:04
  • Yeah I actually used [] in the code, got mixed up here. Commented May 15, 2009 at 17:09

7 Answers 7

61

You'll have to pre-fill it with something (e.g. 0 or None) before you can index it:

myList = [None] * 100  # Create list of 100 'None's
myList[12] = 'a'  # etc.

Alternatively, use a dict instead of a list, as Alex Martelli suggested.

Sign up to request clarification or add additional context in comments.

Comments

29

For a "sparse list" you could use a dict instead:

mylist = {}
mylist[12] = 'a'

etc. If you want an actual list (initialize it with [], not (), of course!-) you need to fill the un-set slots to _some_thing, e.g. None, by a little auxiliary function or by subclassing list.

7 Comments

Judging by the error, I believe he was actually using a list, not a tuple.
it probably won't be the best practice to call your dictionary mylist.
Thanks I need linear access to the item, so I will be able to index from 1 to n, so can't use dictionary.
Sure you can, there are plenty of ways to do that with a dict. i.e. "for k in sorted(mydict.keys()): print mydict[k]"
Indexing from 1 to n in the dictionary still works. for i in range(n): if n in dictionary: print dictionary[n] does what you want.
|
19

Here's a quick list wrapper that will auto-expand your list with zeros if you attempt to assign a value to a index past it's length.

class defaultlist(list):

   def __setitem__(self, index, value):
      size = len(self)
      if index >= size:
         self.extend(0 for _ in range(size, index + 1))

      list.__setitem__(self, index, value)

Now you can do this:

>>> a = defaultlist([1,2,3])
>>> a[1] = 5
[1,5,3]
>>> a[5] = 10
[1,5,3,0,0,10]

1 Comment

Note too that @Pithikos expands this to a list of arbitrary dimensions.
2

Not without populating the other locations in the list with something (like None or an empty string). Trying to insert an element into a list using the code you wrote would result in an IndexError.

There's also mylist.insert, but this code:

myList.insert(12,'a')

would just insert 'a' at the first unoccupied location in the list (which would be 0 using your example).

So, as I said, there has to be something in the list at indexes 0-11 before you can insert something at myList[12].

1 Comment

Indeed, list.insert() is not a correct solution, since inserting an item will move every other indexes.
2

If you don't know the size of the list ahead of time, you could use try/except and then Extend the list in the except:

L = []
def add(i, s):
    try:
        L[i] = s
    except IndexError:
        L.extend([None]*(i-len(L)+1))
        L[i] = s

add(12, 'a')
add(22, 'b')

----- Update ---------------------------------------------
Per tgray's comment: If it is likely that your code will throw an Exception most of the time, you should check the length of the List every time, and avoid the Exceptions:

L = []
def add(i, s):
    size = len(L)
    if i >= size:
        L.extend([None]*(i-size+1))
        L[i] = s

3 Comments

If he is adding items with increasing indexes, the speed could probably be improved by using an 'if' statement instead of a 'try-catch'. In this case you would be catching the exception every time, which is more "expensive" than checking the length of L every time.
Do you have a link to source stating it is more "expensive"? Or by how much? That would be helpful.
Here's a link to the source of my comment: paltman.com/2008/jan/18/…
1

Just in case someone needs, I figured out a soluction for my problem, I needed to calc a lot of factorials, some of them could be repeated, so here is my solution:

factorials = {}

def calcFact(v):
    try:
        return factorials[v]
    except KeyError:
        factorials[v] = math.factorial(v)
        return factorials[v]

Testcase:

calcFact(99000)
calcFact(90900)
calcFact(90090)
calcFact(90009)
calcFact(90009) #repeated
calcFact(90009) #repeated

Results:

Repeating mathematical calc: 1.576 s

Using the above code (a list to store repeated values): 1.011 s

2 Comments

This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post.
@phineas as I said in my answer, this was something that I needed to solve, and that was related with "Populating a list/array by index" as you can notice by reading the code. This is way to solve the question, but with a different example.
1

Building on top of Triptych.. If you want a list of arbitrary dimensions

class dynamiclist(list):
    """ List not needing pre-initialization

    Example:
        l = dynamiclist()
        l[20][1] = 10
        l[21][1] = 20
    """

    def __setitem__(self, index, value):
        size = len(self)
        if index >= size:
            self.extend(dynamiclist() for _ in range(size, index + 1))

        list.__setitem__(self, index, value)

    def __getitem__(self, index):
        size = len(self)
        if index >= size:
            self.extend(dynamiclist() for _ in range(size, index + 1))  # allows dimensions > 1

        return list.__getitem__(self, index)

Example

l = dynamiclist()
l[20][1] = 10
l[21][1] = 20

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.