1

I would like to pluck an item from a list and return a default if not found (instead of usual index exception). Very similar to get(key, default) on a dictionary. After perusing the docs, it feels like I still overlooked a trivial built-in python solution that provides this.

Here's the fastest I could come up with:

def pluck(list_items, index, default=None):
  return dict(zip(range(len(list_items)), list_items)).get(index, default)

s = [1, 2,]
pluck(s, 3, None)

Thanks!

2rs2ts
  • 10,662
  • 10
  • 51
  • 95
rpq
  • 1,287
  • 2
  • 11
  • 9
  • 1
    One point, you should read up on `enumerate`. It's much nicer to look at than `zip(range(len....`. – Silas Ray Jun 13 '13 at 21:35
  • 1
    Not that I'm aware of. Your solution should work, but it seems like creating a new `dict` carries a lot of extra work as opposed to one of these solutions. http://stackoverflow.com/questions/2574636/getting-a-default-value-on-index-out-of-range-in-python – austin Jun 13 '13 at 21:35
  • 1
    I think `return list_items[item] if index < len(list_items) else default` is best solution – oleg Jun 13 '13 at 21:37
  • @rpq: What about negative indices? – martineau Jun 13 '13 at 21:52
  • 1
    @martineau `return list_items[item] if 0 <= item < len(list_items) else default` – kqr Jun 13 '13 at 22:23
  • @martineau: Valid point. My particular use case was for positive indexes only. I was hoping for an answer that was exactly one Python built-in method or function (similar to get() on dict). If it handled both negative and positive indexes, great, if not, great too. – rpq Jun 13 '13 at 23:16
  • @austin: i've read dict() is actually slower than {} as well. – rpq Jun 13 '13 at 23:21
  • @rpq: There's no built-in so you'll have to roll-your-own. IMHO Sylvain's answers are the best as they handle both positive and negative index values. – martineau Jun 14 '13 at 00:57
  • It looks like the answer is no. :) But the answers were awesome +1'd – rpq Aug 19 '13 at 20:24
  • Seriously if you're going to accept such answers then don't waste out time by posting questions here. – Ashwini Chaudhary Aug 20 '13 at 03:53

4 Answers4

5

Depending on how often you expect to try to access outside of the bounds of the array, you either should catch the exception (if failures are expected to be rare), or test that the index is valid and otherwise return the default value.

If failures are expected to be rare, this should probably be the fastest solution:

def pluck(items, index, defval):
    try:
        return items[index]
    except IndexError:
        return defval

If they are expected to be frequent, it is better to check that the index is valid:

def pluck(items, index, defval):
    return items[index] if -len(items) <= index < len(items) else defval

Note that this using negative indexes is valid if abs(index) <= len(items), ie. items[-1] is equivalent to items[len(items)-1].

Sylvain Defresne
  • 42,429
  • 12
  • 75
  • 85
3

To keep it really fast and simple, if you are using only positive indexes:

seq, i = [1, 2, 3], 2
plucked = seq[i] if seq[i:] else None

Otherwise:

def pluck(seq, index, default=None):
    try:
        return seq[index]
    except IndexError:
        return default

if exceptions are the norm:

def pluck(seq, index, default=None):
    return seq[index] if seq[index:] and seq[-index-1:] else default

Both work for negative indexes.

dansalmo
  • 11,506
  • 5
  • 58
  • 53
2

Something like this, it works for negative indexes as well.

def list_get(lis, index, default = None):
   index = index if index >=0 else len(lis) + index
   return lis[index] if 0 <= index < len(lis) else default

>>> lis = range(10)
>>> list_get(lis, 8, 'foo')
8
>>> list_get(lis, 11, 'foo')
'foo'
>>> list_get(lis, -11, 'foo')
'foo'
>>> list_get(lis, -9, 'foo')
1
>>> list_get(lis, -5, 'foo')
5
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
1

It seems like your pluck function can be written as

def pluck(list_items, index, default=None):
  if index>length(list_items)-1
     return default
   else 
      return list_items[index]