Jump to content

Filtering JSON Output: A Very Basic Python Question


Recommended Posts

@deanishe I can't thank you enough for all your patience and helpful explanations.

 

I was completely confused by the order of operation, and ready to throw in the towel last evening. But, thanks to your help, I finally have everything working - which is super helpful for me to build from, etc. Thanks a ton!

 

For others that may see this in the future, I made one minor change to the script above. After noticing that it was matching trailing spaces in a way that differed from Alfred's usual filtering, I  just added a line to remove them. So, now the upper portion reads something like this:

 

if len(sys.argv) < 2:
	theQuery = ""
else:
    theQueryDirty = sys.argv[1]
    theQuery = theQueryDirty.strip()

 

You rock @deanishe

 

WW.gif.437060e0fd8a06816403ecb0ae8b421b.gif

Link to post
1 hour ago, Jasondm007 said:

 


if len(sys.argv) < 2:
	theQuery = ""
else:
    theQueryDirty = sys.argv[1]
    theQuery = theQueryDirty.strip()

 

 

FWIW, this could be shortened to:

 

query = sys.argv[1].strip() if len(sys.argv) > 1 else ''

 

Or a bit more verbosely:

 

query = ''
if len(sys.argv) > 1:
  query = sys.argv[1].strip()

 

Edited by deanishe
Link to post
  • 2 weeks later...

@deanishe I was wondering if I could pick your brain once more?

 

After doing some more testing, I realized that this approach requires your query to match the string exactly (ignoring case, of course). However, I'd prefer for to be a little less strict about this and include circumstances where the elements of a query in the string, but not in the same order.

 

For example, if the user types in "term1 term2" I'd like it to also match scenarios where the string is "term1 term3 term2". At the moment, it will only with match strings with term1 and term2 right next to each other.

 

After doing some reading on this issue, it seemed apparent that I needed to first split my query into a list as follows:

 

theQuery = theQueryDirty.split()

 

Then, it probably made sense to try and use an "all" statement when looking for matches. Is that correct?

 

I've tried numerous iterations of this approach, but I continue screwing them up.

 

Here's a simplified version of the OLD matching approach.

for plobj in plObjListSG:
    match = "smart group sg " + plobj["name"]
    # ignore items that don't match query
    if theQuery and theQuery.lower() not in match.lower():
        continue

    result["items"].append({
        "title": plobj["name"],
        "subtitle": "Global Smart Group",
        "match": match,
        # ...
        # ...
    })

And, here's one of my many iterations of the NEW approach that does not work.

 

for plobj in plObjListSG:
    match = "smart group sg " + plobj["name"]
    # ignore items that don't match query
    if all((theQuery and theQuery.lower() not in matchSG.lower()) for element in theQuery):
        continue

    result["items"].append({
        "title": plobj["name"],
        "subtitle": "Global Smart Group",
        "match": match,
        # ...
        # ...
    })

 

Thanks for any help you can lend!

Link to post
1 hour ago, Jasondm007 said:

if all((theQuery and theQuery.lower() not in matchSG.lower()) for element in theQuery):

 

Of course it doesn’t work. You’re supposed to compare matchSG to element, not theQuery ;)

 

(And where does matchSG come from, anyway?)

 

To match all terms, I would do something like this:

 

# split query into words
terms = query.lower().split()

for d in plObjListSG:
    match = 'smart group sg ' + d['name'].lower()
    for s in terms:
        if s not in match:
            break
    else:
        result['items'].append({...})

 

At this point, I'd probably put the filtering in a separate function.

 

Link to post

@deanishe Thanks a ton for all of the helpful notes and suggestions above. 

 

Among other things, you're absolutely right that I kept screwing up what was being compared, in my previous attempts. I was having a hard time adapting some of the python tutorials I found online. And, as for the unknown variable, matchSG, while this wasn't the cause of my prior failed attempts, I mistakenly added to my simplified example posted above (the real version uses this term instead of match, since it's matching more than one thing).

 

I might be doing something wrong again, but I wasn't able to get your suggested approach to work - though it's definitely closer! In layman's terms, it seems to connect each search term with an OR, where I'd prefer it to be an AND.

 

For example, using this OR/AND description, consider the following:

  • User's Query: term1 term2
  • Items
    • Item 1: term1 term2 term3
      • Match under all approaches
    • Item 2: term2 term1 term3
      • Match under both OR/AND approaches, which my prior approach did not accommodate
    • Item 4: term4 term1
      • Match under current/OR approach, but would prefer for this not to match

In short, using the example above, I'd prefer it only to match queries where term1 and term2 are present, though I don't care about their order or whether there are other terms between them. Does that make sense? My apologies for the, admittedly idiotic, description.

 

Thanks again for all of your help!

Link to post
1 hour ago, Jasondm007 said:

In layman's terms, it seems to connect each search term with an OR, where I'd prefer it to be an AND

 

Oh. I was going for AND. That's what happens when you're writing code snippets but can't run them…

 

Can you upload your workflow somewhere and post a link? I'm not going to try and debug code I can't run.

Link to post

Try this.

 

I've basically rewritten the whole thing to be more sensibly structured. Putting code in separate functions and making sure the script doesn't execute if you try to import a function from it. I also added a couple of workflowy features, like showing a message in Alfred if there was an error or no results, so Alfred doesn't silently show its fallback searches. Also, put your code in a separate file, not in the Script box in Alfred, so you can use a proper editor.

 

Your simple AND match is implemented in match_all().

 

I’ve also added more advanced filtering in ranked_matches() that sorts the results by how well they match the search query, so you can see how it's done. This usually gives you better results. Set the RANK_RESULTS variable to 1 in the workflow’s configuration sheet to turn that on.

 

Hopefully, the comments in the code should make clear what's going on, but if you have any questions, ask away.

Link to post
Posted (edited)

@deanishe I can't thank you enough for all of your help with this script. But hope the beer will help.

 

office.gif.5c2f8860ef25b7064314e18b0aeaba54.gif

 

Thanks a ton for the script, and for including the notation. I'm really looking forward to pouring through it, and applying elements from it to other scripts I was working on. As you know, I was struggling with some basic python and Alfred-related things, and I can now see how the two are integrated. Honestly, I can't thank you enough!

Edited by Jasondm007
typo
Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...