how to search for an element in a list that is inside another list?

Asked

Viewed 49,406 times

7

I have the following list composed of lists.

[['julian', '0', '5'], ['ana', '10', '4']]

and I need to use a function that tells me the position of any element within that list, I tried to use:

elemento = lista.index('julian')

print (elemento)

and hope to return

>>>0,0

but it only works when I specify which of the lists within the main list to look for, how could I make it to search inside all the lists and show the position?

6 answers

7

I didn’t go through the other answers in depth, but I was a little surprised by the amount of code for a simple task. So I propose here another solution:

def search (lista, valor):
    return [(lista.index(x), x.index(valor)) for x in lista if valor in x]

The use of this function, in this case, is:

lista = [['julian', '0', '4'], ['ana', '10', '4']]

def search (lista, valor):
    return [(lista.index(x), x.index(valor)) for x in lista if valor in x]

print(search(lista, "julian")) # [(0, 0)]
print(search(lista, "ana"))    # [(1, 0)]
print(search(lista, "0"))      # [(0, 1)]
print(search(lista, "4"))      # [(0, 2), (1, 2)]
print(search(lista, "foo"))    # []

Explaining a little code:

x in lista if valor in x

will search which is the sub-list which is the desired value, storing this sub-list in x. The value returned will be (lista.index(x), x.index(valor)), where the first will be the sub-list index in the list and the second value the index of the desired value within the sub-list. Note that the value returned will be a list of all occurrences of the value. For example, the value "4" is present twice in the list and therefore has two returned values.

See working on Ideone | Repl.it


The above solution fails when a sub-list has the same value several times. For example, in the input:

lista = [['julian', '0', '4', '4'], ['ana', '10', '4']]

It would be expected that the exit to search(lista, '4') were the pairs (0, 2), (0, 3) and (1, 2). because the first sub-list has twice the value '4', but it is, in fact, just (0, 2) and (1, 2), because it stops searching when it finds the first element. To get around this, I adapted the solution to search for all elements:

def get_all_indexes(lista, valor):
    return (i for i, v in enumerate(lista) if v == valor)

def search(lista, valor):
    return (list(product([indice], get_all_indexes(sublista, valor))) 
        for indice, sublista in enumerate(lista) if valor in sublista)

See working on Ideone | Repl.it

Thus, the exit of search(lista, '4') will be:

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

Just as expected.


Or even easier than that, a simple way:

lista = [['julian', '0', '4', '4'], ['ana', '10', '4']]

def search(lista, valor):
    for i, sublista in enumerate(lista):
        yield from ((i, j) for j, item in enumerate(sublista) if item == valor)

print( list(search(lista, '4')) )  # [(0, 2), (0, 3), (1, 2)]

See working on Ideone | Repl.it

7


For a more concise and pitonic solution, see this response.


You can iterate through the entire list, element by element, looking for the item you want - when you find it, we save the element index to a variable and return it next.

Take an example:

lista = [['julian', '0', '5'], ['ana', '10', '4']]

# vamos criar uma função de 'busca'
def encontrar(elemento):
    pos_i = 0 # variável provisória de índice
    pos_j = 0 # idem

    for i in range (len(lista)): # procurar em todas as listas internas
        for j in range (i): # procurar em todos os elementos nessa lista
            if elemento in lista[i][j]: # se encontrarmos elemento ('ana')
                pos_i = i # guardamos o índice i
                pos_j = j # e o índice j
                break # saímos do loop interno
            break # e do externo
    return (pos_i, pos_j) # e retornamos os índices


r = encontrar('ana') # chamamos a função e salvamos em r
print(r) # imprime índices
print(lista[r[0]][r[1]]) # usa índices na lista como prova

Upshot: resultado da execução do código

P.S. This code will not do if there is more than one element with the same value/name (it will always return the first one that it finds)


Edit:

To search for more than one item with the same name, we can save the result in a new list, this way:

lista = [['julian', '0', '5'], ['ana', '10', '4'], ['10', 'ana', '4']]

def encontrar(elemento):
    lista_pos = [] # vamos salvar nesta nova lista
    for i in range (len(lista)):
        for j in range (i):
            if elemento in lista[i][j]:
                lista_pos.append((i, j)) # aqui adicionamos cada índice na lista
    return lista_pos # removemos os breaks, pois precisamos procurar na lista inteira

r = encontrar('ana')
print(r)
# o próximo print só funciona buscando por 'ana', pois ele espera que
# o retorno seja pelo menos dois elementos
print(lista[r[0][0]][r[0][1]], lista[r[1][0]][r[1][1]])

Upshot: resultado da execução do programa

  • In case the same element exists multiple times, I believe that a yield should solve

  • I think I understood, so if there were more than two lists as in the example I would have to increase the loops?

  • @Julianvitor Editei to search for more than one word occurrence. We just need to remove the breaks, because the program didn’t search the entire list - in addition, we need to save more than one result, so I added a new list - have a look.

5

This code seems long, but it’s only because I tried to do something you could understand:

lista = [['julian', '0', '5'], ['ana', '10', '4']]
print(lista)

procurar = input("Digite quem você procura: ")

for i in lista:
    local = lista.index(i) # Primeiro elemento
    for b in i:
        if b == procurar:
            local2 = lista[local].index(b) # Segundo elemento que está dentro do primeiro elemento, pouco confuso, mas é isso aí
            print("Quem você procura está na posição: lista[{}][{}]".format(local,local2))
            break

print("Quem você procura:",lista[local][local2])

Exit:

>>> [['julian', '0', '5'], ['ana', '10', '4']]
>>> Digite quem você procura: 4
>>> Quem você procura está na posição: lista[1][2]
>>> Quem você procura: 4

3

I did a little different by putting inside a function, so that it gets something more generic.

lista = [ ["julian", "0", "5"], ["ana", "10", "4"] ]

# Realiza a busca dentro da lista
def busca(valor):
    i, j = 0,0 # indides incialmente definidos como 0

    # percorrendo lista externa
    for sub in lista:
        #verificando se o valor buscado esta dentro de alguma lista interna
        if valor in sub:
            # atribuindo o indice do valor buscado a j
            j = sub.index(valor)
            break # sai do loop
        i +=1 # incrementa
    else:
        # caso o valor buscado nao seja encontrado
        return None 

    return i,j


result = busca("julian")
print(result)

Using only one for you can browse the internal lists and then check with the use of in if the value sought is in any of them.

If the variable is j will receive the index of this value and the loop is stopped and then a tuple is returned containing the values of i and j.

If you do not find the for will end the search in all lists and as it did not occur the break will fall into condition Else and then return None because the searched value was not found.

  • +1, one of the only ones that actually works.

0

The previous answers, from what I understand, work well for the given example.

However, if we have an entry with a larger nesting, say [[[1, 2], [[[3]]]]], no solution previously presented will give the position of the element.

For a generic solution, follow a code example that uses recursion to return a tuple that corresponds to the position of the element valor in lista, where each new element of the tuple corresponds to a higher level of nesting.

def busca(lista, valor):
    for el in lista:
        if valor == el:
            return (lista.index(el),)

        if isinstance(el, list):
            x = busca(el, valor)
            if x:
                return (lista.index(el),) + x

    return False

The function busca will return the first occurrence of the element valor on the list lista. It is possible that valor be another list.

Examples of results:

lista = [[1, 2], [[[3]]]] | valor = 3
posição = (1, 0, 0, 0)

lista = [[1, 2], [[[3]]]] | valor = 1
posição = (0, 0)

lista = [1, 2, [1, 2]] | valor = 2
posição = (0,)

lista = [1, 2, [1, 2]] | valor = [1, 2]
posição = (2,)

0

There is a little cleaner way that you can do, basically consists of searching within the list all the objects that are part of the condition, for this we use the filter and the lambda after this, with this list of objects that are belonging to the condition you can pick up the contents through the enumerate

Below is the code section responsible for this:

#Conjunto de dados
data = [['julian', '0', '5'], ['ana', '10', '4']]
finder = 'julian'

#Faz o filtro da lista atraves da condição especificada
condition = filter(lambda x: x[0] == finder, data)
#Converte o filtro para uma lista comum
filters = list(condition)

result = []
#Percorre cada item da lista enumerando
for index, item in enumerate(data):
    if item in filters:
        result.append(index)

Now inside result you have all the indices that match the condition

Browser other questions tagged

You are not signed in. Login or sign up in order to post.