* Using tags searches on objects in python
:PROPERTIES:
:categories: python
:date: 2014/03/24 21:52:13
:updated: 2014/03/24 21:52:13
:END:
I am exploring the possibility of using tags on python objects in conjunction with searches to find sets of objects. Here I want to explore some syntax and methods for doing that.
In org-mode there is a syntax like '+boss+urgent-project1' for =and= and =not= operators and 'A|B' for =or= operators. I think we need [[http://pyparsing.wikispaces.com/Examples][pyparsing]] to untangle this kind of syntax. See http://pyparsing.wikispaces.com/file/view/simpleBool.py for an example. Another alternative might be the natural language toolkit ([[http://www.nltk.org/][nltk]]). Before we dig into those, let us see some python ways of doing the logic.
Below we define some lists containing tags (strings). We
#+BEGIN_SRC python
a = ['A', 'B', 'C']
b = ['A', 'B']
c = ['A', 'C']
d = [ 'B', 'C']
all_lists = [a, b, c, d]
# get functions with tags A and B
print 'A and B ',[x for x in all_lists if ('A' in x) & ('B' in x)]
# A not B
print 'A not B ',[x for x in all_lists if ('A' in x) & ('B' not in x)]
# B or C
print 'B or C ', [x for x in all_lists if ('B' in x) | ('C' in x)]
# B or C but not both
print 'B xor C ',[x for x in all_lists if ('B' in x) ^ ('C' in x)]
#+END_SRC
#+RESULTS:
: A and B [['A', 'B', 'C'], ['A', 'B']]
: A not B [['A', 'C']]
: B or C [['A', 'B', 'C'], ['A', 'B'], ['A', 'C'], ['B', 'C']]
: B xor C [['A', 'B'], ['A', 'C']]
Those are not too bad. Somehow I would have to get pyparsing to generate that syntax. That will take a lot of studying. There are some other ways to do this too. Let us try that out with itertools.
#+BEGIN_SRC python
a = ['A', 'B', 'C']
b = ['A', 'B']
c = ['A', 'C']
d = [ 'B', 'C']
all_lists = [a, b, c, d]
import itertools as it
# ifilter returns an iterator
print 'A and B ', list(it.ifilter(lambda x: ('A' in x) & ('B' in x), all_lists))
#+END_SRC
#+RESULTS:
: A and B [['A', 'B', 'C'], ['A', 'B']]
I do not like this syntax better. The iterator is lazy, so we have to wrap it in a list to get the results. Eventually, I want to do something like these:
#+BEGIN_EXAMPLE
filter('A and B', all_lists)
A or B
A xor B
not A and B
not(A and B)
#+END_EXAMPLE
I think that calls for pyparsing. I think the syntax above is better (more readable) than this:
#+BEGIN_EXAMPLE
filter('A & B', all_lists)
A | B
A ^ B
~A & B
~(A & B)
#+END_EXAMPLE
It is not that obvious though how to get from that syntax to the code I illustrated above though.