Question

In the Python Splunk SDK the ResultsReader object provides an iterable object that returns an OrderedDict when accessed. I would like to store the values contained within that OrderedDict to a set to perform set subtraction against a list of expected values. I am having trouble finding a way to access the values in the OrderedDict in a way that allows me to store them to a set.

Code example:

kwargs_search = {"exec_mode": "normal"}
searchquery = "search index=* earliest=-1d| stats values(host)"

job = service.jobs.create(searchquery, **kwargs_search)
for result in results.ResultsReader(job.results()):
    print result

Returns:

OrderedDict([('values(host)', ['host1', 'host2', ... 'hostN'])])

The 'hostN' values are those that I would like to store in the set.

I've tried:

actual_hosts = set()
for result in results.ResultsReader(job.results()):
    actual_hosts.add(result)

Which returns:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
TypeError: unhashable type: 'OrderedDict'

What is the best way to accomplish what I'm attempting here? Open to any ideas.

Was it helpful?

Solution

If each of the values in your OrderedDict is a list (as in the example posted), then results.values() is a list (or iterable, in python3) of lists. In this case, you can iteratively add them to the set:

actual_hosts = set()
for result in results.ResultsReader(job.results()):
    for hosts in results.values():
        actual_hosts.update(hosts)

If each of the values is a string, the inner loop is not necessary, and you can add results.values() to the set directly:

actual_hosts = set()
for result in results.ResultsReader(job.results()):
    actual_hosts.update(results.values())

OTHER TIPS

result.values() should give you the part ['host1',..

An example of creating a set from the values of a dict (it's the same with an OrderedDict):

d = {
    'a': [1, 2, 3],
    'b': [2, 3, 4]
}

hosts = set().union(*d.itervalues())
# set([1, 2, 3, 4])

Which then extends to:

from itertools import chain
hosts = set().union(*chain.from_iterable(res.values() for res in results.ResultsReader(job.results())))

The explicit loop and update is nicer though :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top