Search code examples
pythonpython-2.7nested-listsrenpy

Python - find _any_ and _all_ matches in a nested list, and return the indices


Okay, so this is a bit of both Python 2.7, and Ren'Py, so bear with me (I'm rusty, so I might just be doing something incredibly stupid)

I have an input:

input default "0" length 20 value VariableInputValue('playstore_search')

This goes on to run a function to check for matches in (currently one) nested list:

if playstore_search.strip():
    $ tempsearch = playstore_search.strip()
    text tempsearch:
        color "#000"
        yalign .5 # this is just temporary to show me what the tempsearch looks like
    $ realtimesearchresult = realtime_search(tempsearch,playstore_recommended)
    if realtimesearchresult:
        text "[realtimesearchresult]":
            color "#000"
            yalign .6

This goes on to call this function:

def realtime_search(searchterm=False,listname=False):
    if searchterm and listname:
        indices = [i for i, s in enumerate(listname) if searchterm in s]
        if indices:
            return indices

And, this is a modified list of what it searches:

default playstore_recommended = [
            ['HSS','Studio Errilhl','hss'],
            ['Making Movies','Droid Productions','makingmovies'],
            ['Life','Fasder','life'],
            ['xMassTransitx','xMTx','xmasstransitx'],
            ['Parental Love','Luxee','parentallove'],
            ['A Broken Family','KinneyX23','abrokenfamily'],
            ['Inevitable Relations','KinneyX23','inevitablerelations'],
            ['The DeLuca Family','HopesGaming','thedelucafamily'],
            ['A Cowboy\'s Story','Noller72','acowboysstory']
]

Now, if I search for hss, it'll find that - and if I search for makingmovies it'll find that - however, if I search for droid (or Droid as it isn't case-insensitive currently) it won't find anything.

So, this is at least a twofold question: 1. How do I make this whole thing case-insensitive 2. How do I make it match partial strings

EDIT:

Okay, so stuff is now sort of working. However, there are still some issues. The complete list to match against is quite a bit more complex than what was posted above, and it seems that it doesn't match on string hits "in the middle of a string" - just on the first word. So, if I have something like this:

[
 ['This is a test string with the words game and move in it'],
 ['This is another test string, also containing game']
]

and I search for "game", one would expect two results. But I get 0. If, however, I search for "this", I get two results.


Solution

  • I recommend converting the entries in the nested-list to lowercase first and then search for the term using find(). Consider following function:

    myListOfLists = [
                ['HSS','Studio Errilhl','hss'],
                ['Making Movies','Droid Productions','makingmovies'],
                ['Life','Fasder','life'],
                ['xMassTransitx','xMTx','xmasstransitx'],
                ['Parental Love','Luxee','parentallove'],
                ['A Broken Family','KinneyX23','abrokenfamily'],
                ['Inevitable Relations','KinneyX23','inevitablerelations'],
                ['The DeLuca Family','HopesGaming','thedelucafamily'],
                ['A Cowboy\'s Story','Noller72','acowboysstory']
    ]
    
    searchFor = 'hss'
    result = [ [ l.lower().find(searchFor) == 0 for l in thisList ] for thisList in myListOfLists ]
    

    Using above code, value of result is:

    [[True, False, True],
     [False, False, False],
     [False, False, False],
     [False, False, False],
     [False, False, False],
     [False, False, False],
     [False, False, False],
     [False, False, False],
     [False, False, False]]
    

    If you wish to find just one boolean value from the entire list of lists do:

    any([any(r) for r in result])
    

    If you use searchFor = 'droid', it should return True as well.


    To find index of True, I recommend using where command from numpy

    import numpy as np
    idx = np.where(result)
    

    For example, searchFor = 'life', value of idx will be:

    (array([2, 2], dtype=int64), array([0, 2], dtype=int64))
    

    To find index without using numpy (not as elegant):

    indices = [ [idx if val else -1 for idx, val in enumerate(r) ] for r in result ]
    

    This will give positive values corresponding to index where match occurs, else will give -1.

    [[-1, -1, -1],
     [-1, -1, -1],
     [0, -1, 2],
     [-1, -1, -1],
     [-1, -1, -1],
     [-1, -1, -1],
     [-1, -1, -1],
     [-1, -1, -1],
     [-1, -1, -1]]
    

    Hope that helps!