6

I want to find the location(s) of a specific item in a list of lists. It should return a list of tuples, where each tuple represents the indexes for a specific instance of the item. For example:

list = [['1', '2', '4', '6'], ['7', '0', '1', '4']]
getPosition('1')  #returns [(0, 0), (1, 2)]
and getPosition('7') #returns [(1,0)]

9 Answers9

8

If you want something that will both

  • find duplicates and
  • handle nested lists (lists of lists of lists of ...)

you can do something like the following:

def get_positions(xs, item):
    if isinstance(xs, list):
        for i, it in enumerate(xs):
            for pos in get_positions(it, item):
                yield (i,) + pos
    elif xs == item:
        yield ()

Testing this:

>>> xs = [['1', '2', '4', '6'],
...       ['7', '0', '1', '4'],
...       [ [ '0', '1', '1'], ['1']]
...       ]
>>> print list(get_positions(xs, '1'))
[(0, 0), (1, 2), (2, 0, 1), (2, 0, 2), (2, 1, 0)]
Rick Copeland
  • 11,672
  • 5
  • 39
  • 38
6

It looks likes you want, for a list of sublists and a given item, to return a list of pairs where each pair is (the index of the sublist, the index of the item within the sublist). You can do that using list comprehensions and Python's built in enumerate() function:

def getPosition(list, item):
    return [(i, sublist.index(item)) for i, sublist in enumerate(list)]

Edit: See @scribble's answer above/below.

a paid nerd
  • 30,702
  • 30
  • 134
  • 179
4
def getPosition(list, item):
    return [(i, sublist.index(item)) for i, sublist in enumerate(list) 
                                                      if item in sublist]
Arkady
  • 14,305
  • 8
  • 42
  • 46
3
def get_positions(xs, target):
    return [(i,e.index(target)) for i,e in enumerate(xs)]

That's a good starting point. Presumably you have some sort of class such as

class SomeClass:
    def __init__(self):
        self.xs = [['1','2','4','6'], ['7','0','1','4']]

    def get_positions(self, target):
        return [(i,e.index(target)) for i,e in enumerate(self.xs)]

which in this case would let you say

model = SomeClass()
model.get_position(1)    # returns [(0,0), (1,2)]

Note that in both cases you'll get an exception if your target isn't in every one of your sublists. The question does not specify whether this is the desired behavior.

Eli Courtwright
  • 186,300
  • 67
  • 213
  • 256
  • I do not believe this fits the question. The argument to 'getPosition' is an element (or sub-element) while the returned value is a position, not the reverse. – Greg Case May 12 '09 at 14:23
  • Yep, I misread it at first, but I've since fixed my code to do the correct thing. – Eli Courtwright May 12 '09 at 14:25
3

If you don't want a exception if the item is not in the list try this. Also as a generator because they are cool and versatile.

xs = [['1', '2', '4', '6'], ['7', '0', '1', '4']]
def get_positions(xs, item):
    for i, xt in enumerate( xs ):
        try: # trying beats checking
            yield (i, xt.index(item))
        except ValueError: 
            pass

print list(get_positions(xs, '1'))
print list(get_positions(xs, '6'))

# Edit for fun: The one-line version, without try:

get_positions2 = lambda xs,item: ((i,xt.index(item)) for  i, xt in enumerate(xs) if item in xt)

print list(get_positions2(xs, '1'))
print list(get_positions2(xs, '6'))
Jochen Ritzel
  • 104,512
  • 31
  • 200
  • 194
1

A while ago I wrote a library for python to do list matching that would fit the bill pretty well. It used the tokens ?, +, and * as wildcards, where ? signifies a single atom, + is a non-greedy one-or-more, and * is greedy one-or-more. For example:

from matching import match

match(['?', 2, 3, '*'], [1, 2, 3, 4, 5])
=> [1, [4, 5]]

match([1, 2, 3], [1, 2, 4])
=> MatchError: broken at 4

match([1, [2, 3, '*']], [1, [2, 3, 4]])
=> [[4]]

match([1, [2, 3, '*']], [1, [2, 3, 4]], True)
=> [1, 2, 3, [4]]

Download it here: http://www.artfulcode.net/wp-content/uploads/2008/12/matching.zip

Jeff Ober
  • 4,967
  • 20
  • 15
1

Here is a version without try..except, returning an iterator and that for

[['1', '1', '1', '1'], ['7', '0', '4']]

returns

[(0, 0), (0, 1), (0, 2), (0, 3)] 


def getPosition1(l, val):
  for row_nb, r in enumerate(l):
      for col_nb in (x for x in xrange(len(r)) if r[x] == val):
         yield row_nb, col_nb
odwl
  • 2,095
  • 2
  • 17
  • 15
  • Note that the following seems even a little bit faster: def getPosition1(l, val): for row_nb, r in enumerate(l): for col_nb, _ in enumerate(item for item in r if item == val): yield row_nb, col_nb – odwl May 12 '09 at 23:30
1

The most strainghtforward and probably the slowest way to do it would be:

    >>> value = '1'
    >>> l = [['1', '2', '3', '4'], ['3', '4', '5', '1']]
    >>> m = []
    >>> for i in range(len(l)):
    ...  for j in range(len(l[i])):
    ...   if l[i][j] == value:
    ...    m.append((i,j))
    ...
    >>> m
    [(0, 0), (1, 3)]
Alex
  • 43,191
  • 44
  • 96
  • 127
1

Here is another straight forward method that doesn't use generators.

def getPosition(lists,item):
    positions = []
    for i,li in enumerate(lists):
        j = -1
        try:
            while True:
                j = li.index(item,j+1)
                positions.append((i,j))
        except ValueError:
            pass
    return positions

l = [['1', '2', '4', '6'], ['7', '0', '1', '4']]
getPosition(l,'1')  #returns [(0, 0), (1, 2)]
getPosition(l,'9') # returns []

l = [['1', '1', '1', '1'], ['7', '0', '1', '4']]
getPosition(l,'1')  #returns [(0, 0), (0, 1), (0,2), (0,3), (1,2)]
randlet
  • 3,628
  • 1
  • 17
  • 21