asq.queryables

Classes which support the Queryable interface.

asq.queryables.Queryable

class asq.queryables.Queryable(iterable)

Queries over iterables executed serially.

Queryable objects are constructed from iterables.

Queryable.__contains__ Support for membership testing using the ‘in’ operator.
Queryable.__enter__ Support for the context manager protocol.
Queryable.__eq__ Determine value equality with another iterable.
Queryable.__exit__ Support for the context manager protocol.
Queryable.__getitem__ Support for indexing into the sequence using square brackets.
Queryable.__init__ Construct a Queryable from any iterable.
Queryable.__iter__ Support for the iterator protocol.
Queryable.__ne__ Determine value inequality with another iterable.
Queryable.__reversed__ Support for sequence reversal using the reversed() built-in.
Queryable.__repr__ Returns a stringified representation of the Queryable.
Queryable.__str__ Returns a stringified representation of the Queryable.
Queryable.aggregate Apply a function over a sequence to produce a single result.
Queryable.all Determine if all elements in the source sequence satisfy a condition.
Queryable.any Determine if the source sequence contains any elements which satisfy the predicate.
Queryable.as_parallel Return a ParallelQueryable for parallel execution of queries.
Queryable.average Return the arithmetic mean of the values in the sequence..
Queryable.close Closes the queryable.
Queryable.closed Determine whether the Queryable has been closed.
Queryable.concat Concatenates two sequences.
Queryable.contains Determines whether the sequence contains a particular value.
Queryable.count Return the number of elements (which match an optional predicate).
Queryable.default_if_empty If the source sequence is empty return a single element sequence containing the supplied default value, otherwise return the source sequence unchanged.
Queryable.difference Returns those elements which are in the source sequence which are not in the second_iterable.
Queryable.distinct Eliminate duplicate elements from a sequence.
Queryable.element_at Return the element at ordinal index.
Queryable.first The first element in a sequence (optionally satisfying a predicate).
Queryable.first_or_default The first element (optionally satisfying a predicate) or a default.
Queryable.group_by Groups the elements according to the value of a key extracted by a selector function.
Queryable.group_join Match elements of two sequences using keys and group the results.
Queryable.intersect Returns those elements which are both in the source sequence and in the second_iterable.
Queryable.join Perform an inner join with a second sequence using selected keys.
Queryable.last The last element in a sequence (optionally satisfying a predicate).
Queryable.last_or_default The last element (optionally satisfying a predicate) or a default.
Queryable.log Log query result consumption details to a logger.
Queryable.max Return the maximum value in a sequence.
Queryable.min Return the minimum value in a sequence.
Queryable.of_type Filters elements according to whether they are of a certain type.
Queryable.order_by Sorts by a key in ascending order.
Queryable.order_by_descending Sorts by a key in descending order.
Queryable.select Transforms each element of a sequence into a new form.
Queryable.select_many Projects each element of a sequence to an intermediate new sequence, flattens the resulting sequences into one sequence and optionally transforms the flattened sequence using a selector function.
Queryable.select_many_with_correspondence Projects each element of a sequence to an intermediate new sequence, and flattens the resulting sequence, into one sequence and uses a selector function to incorporate the corresponding source for each item in the result sequence.
Queryable.select_many_with_index Projects each element of a sequence to an intermediate new sequence, incorporating the index of the element, flattens the resulting sequence into one sequence and optionally transforms the flattened sequence using a selector function.
Queryable.select_with_correspondence Apply a callable to each element in an input sequence, generating a new sequence of 2-tuples where the first element is the input value and the second is the transformed input value.
Queryable.select_with_index Transforms each element of a sequence into a new form, incorporating the index of the element.
Queryable.sequence_equal Determine whether two sequences are equal by elementwise comparison.
Queryable.single The only element (which satisfies a condition).
Queryable.single_or_default The only element (which satisfies a condition) or a default.
Queryable.skip Skip the first count contiguous elements of the source sequence.
Queryable.skip_while Omit elements from the start for which a predicate is True.
Queryable.sum Return the arithmetic sum of the values in the sequence..
Queryable.take Returns a specified number of elements from the start of a sequence.
Queryable.take_while Returns elements from the start while the predicate is True.
Queryable.to_dictionary Build a dictionary from the source sequence.
Queryable.to_list Convert the source sequence to a list.
Queryable.to_lookup Returns a Lookup object, using the provided selector to generate a key for each item.
Queryable.to_set Convert the source sequence to a set.
Queryable.to_str Build a string from the source sequence.
Queryable.to_tuple Convert the source sequence to a tuple.
Queryable.union Returns those elements which are either in the source sequence or in the second_iterable, or in both.
Queryable.where Filters elements according to whether they match a predicate.
Queryable.zip Elementwise combination of two sequences.
__contains__(item)

Support for membership testing using the ‘in’ operator.

Parameters:item – The item for which to test membership.
Returns:True if item is in the sequence, otherwise False.

Note

A chainable query operator called contains() (no underscores) is also provided.

Example

Test whether 49 is one of the squares of two, seven or nine:

>>> a = [2, 7, 9]
>>> 49 in query(a).select(lambda x: x*x)
True
__enter__()

Support for the context manager protocol.

__eq__(rhs)

Determine value equality with another iterable.

Parameters:rhs – Any iterable collection.
Returns:True if the sequences are equal in value, otherwise False.

Note

This in the infix operator equivalent of the sequence_equal() query operator.

Examples

Test whether a sequence is equal to a list:

>>> expected = [2, 4, 8, 16, 32]
>>> range(1, 5).select(lambda x: x ** 2) == expected
True
__exit__(type, value, traceback)

Support for the context manager protocol.

Ensures that close() is called on the Queryable.

__getitem__(index)

Support for indexing into the sequence using square brackets.

Equivalent to element_at().

Parameters:

index – The index should be between zero and count() - 1 inclusive. Negative indices are not interpreted in the same way they are for built-in lists, and are considered out-of-range.

Returns:

The value of the element at offset index into the sequence.

Raises:
  • ValueError - If the Queryable is closed().
  • IndexError - If the index is out-of-range.

Note

A chainable query operator called element_at() is also provided.

Examples

Retrieve the fourth element of a greater than six:

>>> a = [7, 3, 9, 2, 1, 10, 11, 4, 13]
>>> query(a).where(lambda x: x > 6)[3]
11
__init__(iterable)

Construct a Queryable from any iterable.

Parameters:iterable – Any object supporting the iterator protocol.
Raises:TypeError - if iterable does not support the iterator protocol.

Example

Initialise a queryable from a list:

>>> a = [1, 5, 7, 8]
>>> queryable = Queryable(a)

Note

The query(iterable) initiator should normally be used in preference to calling the Queryable constructor directly.

__iter__()

Support for the iterator protocol.

Allows Queryable instances to be used anywhere an iterable is required.

Returns:An iterator over the values in the query result.
Raises:ValueError - If the Queryable has been closed().

Note

This method should not usually be called directly; use the iter() built-in or other Python constructs which check for the presence of __iter__(), such as for loops.

Examples

Call __iter__() indirectly through the iter() built-in to obtain an iterator over the query results:

>>> a = [8, 9, 2]
>>> q = query(a)
>>> iterator = iter(q)
>>> next(iterator)
8
>>> next(iterator)
9
>>> next(iterator)
2
>>> next(iterator)
StopIteration

Call __iter__() indirectly by using a for loop:

>>> a = [1, 9, 4]
>>> q = query(a)
>>> for v in q:
...     print(v)
...
1
9
4
__ne__(rhs)

Determine value inequality with another iterable.

Parameters:rhs – Any iterable collection.
Returns:True if the sequences are inequal in value, otherwise False.

Examples

Test whether a sequence is not equal to a list:

>>> expected = [1, 2, 3]
>>> range(1, 5).select(lambda x: x ** 2) != expected
True
__reversed__()

Support for sequence reversal using the reversed() built-in.

Called by reversed() to implement reverse iteration.

Equivalent to the reverse() method.

Returns:A Queryable over the reversed sequence.
Raises:ValueError - If the Queryable is closed().

Note

A chainable query operator called reverse() is also provided.

Note

This method should not usually be called directly; use the reversed() built-in or other Python constructs which check for the presence of __reversed__().

Example

Create a reverse iterator over a queryable for use with a for loop:

>>> a = [7, 3, 9, 2, 1]
>>> q = query(a)
>>> for v in reversed(q):
...     print(v)
...
1
2
9
3
7
__repr__()

Returns a stringified representation of the Queryable.

The string will not necessarily contain the sequence data.

Returns:A stringified representation of the Queryable.

Note

This method should not usually be called directly; use the str() built-in or other Python constructs which check for the presence of __str__ such as string interpolation functions.

Provide a string representation of the Queryable using the repr() built-in:

>>> a = [9, 7, 8]
>>> q = query(a)
>>> str(q)
'Queryable([9, 7, 8])'
__str__()

Returns a stringified representation of the Queryable.

The string will necessarily contain the sequence data.

Returns:A stringified representation of the Queryable.

Note

This method should not usually be called directly; use the str() built-in or other Python constructs which check for the presence of __str__ such as string interpolation functions.

Note

In order to convert the Queryable sequence to a string based on the element values, consider using the to_str() method.

Example

Convert the Queryable to a string using the str() built-in:

>>> a = [9, 7, 8]
>>> q = query(a)
>>> str(q)
'Queryable([9, 7, 8])'
aggregate(reducer, seed=sentinel, result_selector=identity)

Apply a function over a sequence to produce a single result.

Apply a binary function cumulatively to the elements of the source sequence so as to reduce the iterable to a single value.

Note

This method uses immediate execution.

Parameters:
  • reducer – A binary function the first positional argument of which is an accumulated value and the second is the update value from the source sequence. The return value should be the new accumulated value after the update value has been incorporated.
  • seed – An optional value used to initialise the accumulator before iteration over the source sequence. If seed is omitted the and the source sequence contains only one item, then that item is returned.
  • result_selector – An optional unary function applied to the final accumulator value to produce the result. If omitted, defaults to the identity function.
Raises:
  • ValueError - If called on an empty sequence with no seed value.
  • TypeError - If reducer is not callable.
  • TypeError - If result_selector is not callable.

Examples

Compute the product of a list of numbers:

>>> numbers = [4, 7, 3, 2, 1, 9]
>>> query(numbers).aggregate(lambda accumulator, update: accumulator * update)
1512

Concatenate strings to an initial seed value:

>>> cheeses = ['Cheddar', 'Stilton', 'Cheshire', 'Beaufort', 'Brie']
>>> query(cheeses).aggregate(lambda a, u: a + ' ' + u, seed="Cheeses:")
'Cheeses: Cheddar Stilton Cheshire Beaufort Brie'

Concatenate text fragments using operator.add() and return the number of words:

>>> from operator import add
>>> fragments = ['The quick ', 'brown ', 'fox jumped over ', 'the ', 'lazy dog.']
>>> query(fragments).aggregate(add, lambda result: len(result.split()))
9
all(predicate=bool)

Determine if all elements in the source sequence satisfy a condition.

All of the source sequence will be consumed.

Note

This method uses immediate execution.

Parameters:

predicate (callable) – An optional single argument function used to test each elements. If omitted, the bool() function is used resulting in the elements being tested directly.

Returns:

True if all elements in the sequence meet the predicate condition, otherwise False.

Raises:
  • ValueError - If the Queryable is closed()
  • TypeError - If predicate is not callable.

Examples

Determine whether all values evaluate to True in a boolean context:

>>> items = [5, 2, "camel", 3.142, (3, 4, 9)]
>>> query(objects).all()
True

Check that all numbers are divisible by 13:

>>> numbers = [260, 273, 286, 299, 312, 325, 338, 351, 364, 377]
>>> query(numbers).all(lambda x: x % 13 == 0)
True
any(predicate=None)

Determine if the source sequence contains any elements which satisfy the predicate.

Only enough of the sequence to satisfy the predicate once is consumed.

Note

This method uses immediate execution.

Parameters:predicate – An optional single argument function used to test each element. If omitted, or None, this method returns True if there is at least one element in the source.
Returns:True if the sequence contains at least one element which satisfies the predicate, otherwise False.
Raises:ValueError - If the Queryable is closed()

Examples

Determine whether the sequence contains any items:

>>> items = [0, 0, 0]
>>> query(items).any()
True

Determine whether the sequence contains any items which are a multiple of 13:

>>> numbers = [98, 458, 32, 876, 12, 9, 325]
>>> query(numbers).any(lambda x: x % 13 == 0)
True
as_parallel(pool=None)

Return a ParallelQueryable for parallel execution of queries.

Warning

This feature should be considered experimental alpha quality.

Parameters:pool – An optional multiprocessing pool which will provide execution resources for parellel processing. If omitted, a pool will be created if necessary and managed internally.
Returns:A ParallelQueryable on which all the standard query operators may be called.
average(selector=identity)

Return the arithmetic mean of the values in the sequence..

All of the source sequence will be consumed.

Note

This method uses immediate execution.

Parameters:

selector – An optional single argument function which will be used to project the elements of the sequence. If omitted, the identity function is used.

Returns:

The arithmetic mean value of the projected sequence.

Raises:
  • ValueError - If the Queryable has been closed.
  • ValueError - I the source sequence is empty.

Examples

Compute the average of some numbers:

>>> numbers = [98, 458, 32, 876, 12, 9, 325]
>>> query(numbers).average()
258.57142857142856

Compute the mean square of a sequence:

>>> numbers = [98, 458, 32, 876, 12, 9, 325]
>>> query(numbers).average(lambda x: x*x)
156231.14285714287
close()

Closes the queryable.

The Queryable should not be used following a call to close. This method is idempotent. Other calls to a Queryable following close() will raise ValueError.

closed()

Determine whether the Queryable has been closed.

Returns:True if closed, otherwise False.
concat(second_iterable)

Concatenates two sequences.

Note

This method uses deferred execution.

Parameters:

second_iterable – The sequence to concatenate on to the sequence.

Returns:

A Queryable over the concatenated sequences.

Raises:
  • ValueError - If the Queryable is closed().
  • TypeError - If second_iterable is not in fact iterable.

Example

Concatenate two sequences of numbers:

>>> numbers = [1, 45, 23, 34]
>>> query(numbers).concat([98, 23, 23, 12]).to_list()
[1, 45, 23, 34, 98, 23, 23, 12]
contains(value, equality_comparer=operator.eq)

Determines whether the sequence contains a particular value.

Execution is immediate. Depending on the type of the sequence, all or none of the sequence may be consumed by this operation.

Note

This method uses immediate execution.

Parameters:value – The value to test for membership of the sequence
Returns:True if value is in the sequence, otherwise False.
Raises:ValueError - If the Queryable has been closed.

Example

Check whether a sentence contains a particular word:

>>> words = ['A', 'man', 'a', 'plan', 'a', 'canal', 'Panama']
>>> words.contains('plan')
True

Check whether a sentence contains a particular word with a case- insensitive check:

>>> words = ['A', 'man', 'a', 'plan', 'a', 'canal', 'Panama']
>>> query(words).contains('panama',
...                     lambda lhs, rhs: lhs.lower() == rhs.lower())
True
count(predicate=None)

Return the number of elements (which match an optional predicate).

Note

This method uses immediate execution.

Parameters:

predicate – An optional unary predicate function used to identify elements which will be counted. The single positional argument of the function is the element value. The function should return True or False.

Returns:

The number of elements in the sequence if the predicate is None (the default), or if the predicate is supplied the number of elements for which the predicate evaluates to True.

Raises:
  • ValueError - If the Queryable is closed().
  • TypeError - If predicate is neither None nor a callable.

Examples

Count the number of elements in a sequence:

>>> people = ['Sheila', 'Jim', 'Fred']
>>> query(people).count()
3

Count the number of names containing the letter ‘i’:

>>> people = ['Sheila', 'Jim', 'Fred']
>>> query(people).count(lambda s: 'i' in s)
3
default_if_empty(default)

If the source sequence is empty return a single element sequence containing the supplied default value, otherwise return the source sequence unchanged.

Note

This method uses deferred execution.

Parameters:default – The element to be returned if the source sequence is empty.
Returns:The source sequence, or if the source sequence is empty an sequence containing a single element with the supplied default value.
Raises:ValueError - If the Queryable has been closed.

Examples

An empty sequence triggering the default return:

>>> e = []
>>> query(e).default_if_empty(97).to_list()
[97]

A non-empty sequence passing through:

>>> f = [70, 45, 34]
>>> query(f).default_if_empty(97).to_list()
[70, 45, 34]
difference(second_iterable, selector=identity)

Returns those elements which are in the source sequence which are not in the second_iterable.

This method is equivalent to the Except() LINQ operator, renamed to a valid Python identifier.

Note

This method uses deferred execution, but as soon as execution commences the entirety of the second_iterable is consumed; therefore, although the source sequence may be infinite the second_iterable must be finite.

Parameters:
  • second_iterable – Elements from this sequence are excluded from the returned sequence. This sequence will be consumed in its entirety, so must be finite.
  • selector – A optional single argument function with selects from the elements of both sequences the values which will be compared for equality. If omitted the identity function will be used.
Returns:

A sequence containing all elements in the source sequence except those which are also members of the second sequence.

Raises:
  • ValueError - If the Queryable has been closed.
  • TypeError - If the second_iterable is not in fact iterable.
  • TypeError - If the selector is not callable.

Examples

Numbers in the first list which are not in the second list:

>>> a = [0, 2, 4, 5, 6, 8, 9]
>>> b = [1, 3, 5, 7, 8]
>>> query(a).difference(b).to_list()
[0, 2, 4, 6, 9]

Countries in the first list which are not in the second list, compared in a case-insensitive manner:

>>> a = ['UK', 'Canada', 'qatar', 'china', 'New Zealand', 'Iceland']
>>> b = ['iceland', 'CANADA', 'uk']
>>> query(a).difference(b, lambda x: x.lower()).to_list()
['qatar', 'china', 'New Zealand']
distinct(selector=identity)

Eliminate duplicate elements from a sequence.

Note

This method uses deferred execution.

Parameters:

selector – An optional single argument function the result of which is the value compared for uniqueness against elements already consumed. If omitted, the element value itself is compared for uniqueness.

Returns:

Unique elements of the source sequence as determined by the selector function. Note that it is unprojected elements that are returned, even if a selector was provided.

Raises:
  • ValueError - If the Queryable is closed.
  • TypeError - If the selector is not callable.

Examples

Remove duplicate numbers:

>>> d = [0, 2, 4, 5, 6, 8, 9, 1, 3, 5, 7, 8]
>>> query(d).distinct().to_list()
[0, 2, 4, 5, 6, 8, 9, 1, 3, 7]

A sequence such that no two numbers in the result have digits which sum to the same value:

>>> e = [10, 34, 56, 43, 74, 25, 11, 89]
>>> def sum_of_digits(num):
...     return sum(int(i) for i in str(num))
...
>>> query(e).distinct(sum_of_digits).to_list()
[10, 34, 56, 11, 89]
element_at(index)

Return the element at ordinal index.

Note

This method uses immediate execution.

Parameters:

index – The index of the element to be returned.

Returns:

The element at ordinal index in the source sequence.

Raises:
  • ValueError - If the Queryable is closed().
  • ValueError - If index is out of range.

Example

Retrieve the fifth element from a list:

>>> f = [10, 34, 56, 11, 89]
>>> query(f).element_at(4)
89
first(predicate=None)

The first element in a sequence (optionally satisfying a predicate).

If the predicate is omitted or is None this query returns the first element in the sequence; otherwise, it returns the first element in the sequence for which the predicate evaluates to True. Exceptions are raised if there is no such element.

Note

This method uses immediate execution.

Parameters:

predicate – An optional unary predicate function, the only argument to which is the element. The return value should be True for matching elements, otherwise False. If the predicate is omitted or None the first element of the source sequence will be returned.

Returns:

The first element of the sequence if predicate is None, otherwise the first element for which the predicate returns True.

Raises:
  • ValueError - If the Queryable is closed.
  • ValueError - If the source sequence is empty.
  • ValueError - If there are no elements matching the predicate.
  • TypeError - If the predicate is not callable.

Examples

Retrieve the first element of a sequence:

>>> e = [10, 34, 56, 43, 74, 25, 11, 89]
>>> query(e).first()
10

Retrieve the first element of a sequence divisible by seven:

>>> e = [10, 34, 56, 43, 74, 25, 11, 89]
>>> query(e).first(lambda x: x % 7 == 0)
56
first_or_default(default, predicate=None)

The first element (optionally satisfying a predicate) or a default.

If the predicate is omitted or is None this query returns the first element in the sequence; otherwise, it returns the first element in the sequence for which the predicate evaluates to True. If there is no such element the value of the default argument is returned.

Note

This method uses immediate execution.

Parameters:
  • default – The value which will be returned if either the sequence is empty or there are no elements matching the predicate.
  • predicate – An optional unary predicate function, the only argument to which is the element. The return value should be True for matching elements, otherwise False. If the predicate is omitted or None the first element of the source sequence will be returned.
Returns:

The first element of the sequence if predicate is None, otherwise the first element for which the predicate returns True. If there is no such element, the default argument is returned.

Raises:
  • ValueError - If the Queryable is closed.
  • TypeError - If the predicate is not callable.

Examples

Retrieve the first element of a sequence:

>>> e = [10, 34, 56, 43, 74, 25, 11, 89]
>>> query(e).first_or_default(14)
10

Return the default when called on an empty sequence:

>>> f = []
>>> query(f).first_or_default(17)
17

Retrieve the first element of a sequence divisible by eight:

>>> e = [10, 34, 56, 43, 74, 25, 11, 89]
>>> query(e).first_or_default(10, lambda x: x % 8 == 0)
56
group_by(key_selector=identity, element_selector=identity, result_selector=lambda key, grouping: grouping)

Groups the elements according to the value of a key extracted by a selector function.

Note

This method has different behaviour to itertools.groupby in the Python standard library because it aggregates all items with the same key, rather than returning groups of consecutive items of the same key.

Note

This method uses deferred execution, but consumption of a single result will lead to evaluation of the whole source sequence.

Parameters:
  • key_selector – An optional unary function used to extract a key from each element in the source sequence. The default is the identity function.
  • element_selector – A optional unary function to map elements in the source sequence to elements in a resulting Grouping. The default is the identity function.
  • result_selector – An optional binary function to create a result from each group. The first positional argument is the key identifying the group. The second argument is a Grouping object containing the members of the group. The default is a function which simply returns the Grouping.
Returns:

A Queryable sequence of elements of the where each element represents a group. If the default result_selector is relied upon this is a Grouping object.

Raises:
  • ValueError - If the Queryable is closed().
  • TypeError - If key_selector is not callable.
  • TypeError - If element_selector is not callable.
  • TypeError - If result_selector is not callable.

Examples

Group numbers by the remainder when dividing them by five:

>>> numbers = [10, 34, 56, 43, 74, 25, 11, 89]
>>> groups = query(e).group_by(lambda x: x % 5).to_list()
>>> groups
[Grouping(key=0), Grouping(key=4), Grouping(key=1),
 Grouping(key=3)]
>>> groups[0].key
0
>>> groups[0].to_list()
[10, 25]
>>> groups[1].key
1
>>> groups[1].to_list()
[34, 74, 89]

Group people by their nationality of the first name, and place only the person’s name in the grouped result:

>>> people = [ dict(name="Joe Bloggs", nationality="British"),
...            dict(name="Ola Nordmann", nationality="Norwegian"),
...            dict(name="Harry Holland", nationality="Dutch"),
...            dict(name="Kari Nordmann", nationality="Norwegian"),
...            dict(name="Jan Kowalski", nationality="Polish"),
...            dict(name="Hans Schweizer", nationality="Swiss"),
...            dict(name="Tom Cobbleigh", nationality="British"),
...            dict(name="Tommy Atkins", nationality="British") ]
>>> groups = query(people).group_by(lambda p: p['nationality'],
                                  lambda p: p['name']).to_list()
>>> groups
[Grouping(key='British'), Grouping(key='Norwegian'),
 Grouping(key='Dutch'), Grouping(key='Polish'),
 Grouping(key='Swiss')]
>>> groups[0].to_list()
['Joe Bloggs', 'Tom Cobbleigh', 'Tommy Atkins']
>>> groups[1].to_list()
['Ola Nordmann', 'Kari Nordmann']

Determine the number of people in each national group by creating a tuple for each group where the first element is the nationality and the second element is the number of people of that nationality:

>>> people = [ dict(name="Joe Bloggs", nationality="British"),
...            dict(name="Ola Nordmann", nationality="Norwegian"),
...            dict(name="Harry Holland", nationality="Dutch"),
...            dict(name="Kari Nordmann", nationality="Norwegian"),
...            dict(name="Jan Kowalski", nationality="Polish"),
...            dict(name="Hans Schweizer", nationality="Swiss"),
...            dict(name="Tom Cobbleigh", nationality="British"),
...            dict(name="Tommy Atkins", nationality="British") ]
>>> groups = query(people).group_by(lambda p: p['nationality'],
...  result_selector=lambda key, group: (key, len(group))).to_list()
>>> groups
[('British', 3), ('Norwegian', 2), ('Dutch', 1), ('Polish', 1),
 ('Swiss', 1)]
group_join(inner_iterable, outer_key_selector=identity, inner_key_selector=identity, result_selector=lambda outer, grouping: grouping)

Match elements of two sequences using keys and group the results.

The group_join() query produces a hierarchical result, with all of the inner elements in the result grouped against the matching outer element.

The order of elements from outer is maintained. For each of these the order of elements from inner is also preserved.

Note

This method uses deferred execution.

Parameters:
  • inner_iterable – The sequence to join with the outer sequence.
  • outer_key_selector – An optional unary function to extract keys from elements of the outer (source) sequence. The first positional argument of the function should accept outer elements and the result value should be the key. If omitted, the identity function is used.
  • inner_key_selector – An optional unary function to extract keys from elements of the inner_iterable. The first positional argument of the function should accept outer elements and the result value should be the key. If omitted, the identity function is used.
  • result_selector – An optional binary function to create a result element from an outer element and the Grouping of matching inner elements. The first positional argument is the outer elements and the second in the Grouping of inner elements which match the outer element according to the key selectors used. If omitted, the result elements will be the Groupings directly.
Returns:

A Queryable over a sequence with one element for each group in the result as returned by the result_selector. If the default result selector is used, the result is a sequence of Grouping objects.

Raises:
  • ValueError - If the Queryable has been closed.
  • TypeError - If the inner_iterable is not in fact iterable.
  • TypeError - If the outer_key_selector is not callable.
  • TypeError - If the inner_key_selector is not callable.
  • TypeError - If the result_selector is not callable.

Example

Correlate players with soccer teams using the team name. Group the players within those teams such that each element of the result sequence contains full information about a team and a collection of players belonging to that team:

>>> players = [dict(name="Ferdinand", team="Manchester United"),
...            dict(name="Cole", team="Chelsea", fee=5),
...            dict(name="Crouch", team="Tottenham Hotspur"),
...            dict(name="Downing", team="Aston Villa"),
...            dict(name="Lampard", team="Chelsea", fee=11),
...            dict(name="Rooney", team="Manchester United"),
...            dict(name="Scholes", team="Manchester United", fee=None)]
>>> teams = [dict(name="Manchester United", ground="Old Trafford"),
...          dict(name="Chelsea", ground="Stamford Bridge"),
...          dict(name="Tottenham Hotspur", ground="White Hart Lane"),
...          dict(name="Aston Villa", ground="Villa Park")]
>>> q = query(teams).group_join(players, lambda team: team['name'],
...               lambda player: player['team'],
...               lambda team, grouping: dict(team=team['name'],
...                                           ground=team['ground'],
...                                           players=grouping)).to_list()
>>> q
[{'players': Grouping(key='Manchester United'), 'ground': 'Old Trafford', 'team': 'Manchester United'},
 {'players': Grouping(key='Chelsea'), 'ground': 'Stamford Bridge', 'team': 'Chelsea'},
 {'players': Grouping(key='Tottenham Hotspur'), 'ground': 'White Hart Lane', 'team': 'Tottenham Hotspur'},
 {'players': Grouping(key='Aston Villa'), 'ground': 'Villa Park', 'team': 'Aston Villa'}]
>>> q[0]['players'].to_list()
[{'name': 'Ferdinand', 'team': 'Manchester United'},
 {'name': 'Rooney', 'team': 'Manchester United'},
 {'name': 'Scholes', 'team': 'Manchester United'}]
intersect(second_iterable, selector=identity)

Returns those elements which are both in the source sequence and in the second_iterable.

Note

This method uses deferred execution.

Parameters:
  • second_iterable – Elements are returned if they are also in the sequence.
  • selector – An optional single argument function which is used to project the elements in the source and second_iterables prior to comparing them. If omitted the identity function will be used.
Returns:

A sequence containing all elements in the source sequence which are also members of the second sequence.

Raises:
  • ValueError - If the Queryable has been closed.
  • TypeError - If the second_iterable is not in fact iterable.
  • TypeError - If the selector is not callable.

Examples

Find all the numbers common to both lists a and b:

>>> a = [1, 6, 4, 2, 6, 7, 3, 1]
>>> b = [6, 2, 1, 9, 2, 5]
>>> query(a).intersect(b).to_list()
[1, 6, 2]

Take those strings from the list a which also occur in list b when compared in a case-insensitive way:

>>> a = ["Apple", "Pear", "Banana", "Orange", "Strawberry"]
>>> b = ["PEAR", "ORANGE", "BANANA", "RASPBERRY", "BLUEBERRY"]
>>> query(a).intersect(b, lambda s: s.lower()).to_list()
['Pear', 'Banana', 'Orange']
join(inner_iterable, outer_key_selector=identity, inner_key_selector=identity, result_selector=lambda outer, inner: (outer, inner))

Perform an inner join with a second sequence using selected keys.

The order of elements from outer is maintained. For each of these the order of elements from inner is also preserved.

Note

This method uses deferred execution.

Parameters:
  • inner_iterable – The sequence to join with the outer sequence.
  • outer_key_selector – An optional unary function to extract keys from elements of the outer (source) sequence. The first positional argument of the function should accept outer elements and the result value should be the key. If omitted, the identity function is used.
  • inner_key_selector – An optional unary function to extract keys from elements of the inner_iterable. The first positional argument of the function should accept outer elements and the result value should be the key. If omitted, the identity function is used.
  • result_selector – An optional binary function to create a result element from two matching elements of the outer and inner. If omitted the result elements will be a 2-tuple pair of the matching outer and inner elements.
Returns:

A Queryable whose elements are the result of performing an inner- join on two sequences.

Raises:
  • ValueError - If the Queryable has been closed.
  • TypeError - If the inner_iterable is not in fact iterable.
  • TypeError - If the outer_key_selector is not callable.
  • TypeError - If the inner_key_selector is not callable.
  • TypeError - If the result_selector is not callable.

Examples

Correlate pets with their owners, producing pairs of pet and owner date for each result:

>>> people = ['Minnie', 'Dennis', 'Roger', 'Beryl']
>>> pets = [dict(name='Chester', owner='Minnie'),
...         dict(name='Gnasher', owner='Dennis'),
...         dict(name='Dodge', owner='Roger'),
...         dict(name='Pearl', owner='Beryl')]
>>> query(pets).join(people, lambda pet: pet['owner']).to_list()
[({'owner': 'Minnie', 'name': 'Chester'}, 'Minnie'),
 ({'owner': 'Dennis', 'name': 'Gnasher'}, 'Dennis'),
 ({'owner': 'Roger', 'name': 'Dodge'}, 'Roger'),
 ({'owner': 'Beryl', 'name': 'Pearl'}, 'Beryl')]

or correlate owners with pets, producing more refined results:

>>> query(people).join(pets, inner_key_selector=lambda pet: pet['owner'],
...   result_selector=lambda person, pet: pet['name'] + " is owned by " + person) \
...   .to_list()
['Chester is owned by Minnie',
 'Gnasher is owned by Dennis',
 'Dodge is owned by Roger',
 'Pearl is owned by Beryl']
last(predicate=None)

The last element in a sequence (optionally satisfying a predicate).

If the predicate is omitted or is None this query returns the last element in the sequence; otherwise, it returns the last element in the sequence for which the predicate evaluates to True. Exceptions are raised if there is no such element.

Note

This method uses immediate execution.

Parameters:

predicate – An optional unary predicate function, the only argument to which is the element. The return value should be True for matching elements, otherwise False. If the predicate is omitted or None the last element of the source sequence will be returned.

Returns:

The last element of the sequence if predicate is None, otherwise the last element for which the predicate returns True.

Raises:
  • ValueError - If the Queryable is closed.
  • ValueError - If the source sequence is empty.
  • ValueError - If there are no elements matching the predicate.
  • TypeError - If the predicate is not callable.

Examples

Return the last number in this sequence:

>>> numbers = [1, 45, 23, 34]
>>> query(numbers).last()
34

Return the last number under 30 in this sequence:

>>> numbers = [1, 45, 23, 34]
>>> query(numbers).last(lambda x: x < 30)
23
last_or_default(default, predicate=None)

The last element (optionally satisfying a predicate) or a default.

If the predicate is omitted or is None this query returns the last element in the sequence; otherwise, it returns the last element in the sequence for which the predicate evaluates to True. If there is no such element the value of the default argument is returned.

Note

This method uses immediate execution.

Parameters:
  • default – The value which will be returned if either the sequence is empty or there are no elements matching the predicate.
  • predicate – An optional unary predicate function, the only argument to which is the element. The return value should be True for matching elements, otherwise False. If the predicate is omitted or None the last element of the source sequence will be returned.
Returns:

The last element of the sequence if predicate is None, otherwise the last element for which the predicate returns True. If there is no such element, the default argument is returned.

Raises:
  • ValueError - If the Queryable is closed.
  • TypeError - If the predicate is not callable.

Examples

Return the last number in this sequence:

>>> numbers = [1, 45, 23, 34]
>>> query(numbers).last()
34

Return the last number under 30 in this sequence:

>>> numbers = [1, 45, 23, 34]
>>> query(numbers).last(lambda x: x < 30)
23

Trigger return of the default using a sequence with no values which satisfy the predicate:

>>> numbers = [1, 45, 23, 34]
>>> query(numbers).last_or_default(100, lambda x: x > 50)
100

Trigger return of the default using an empty sequence:

>>> numbers = []
>>> query(numbers).last_or_default(37)
37
log(logger=None, label=None, eager=False)

Log query result consumption details to a logger.

Parameters:
  • logger – Any object which supports a debug() method which accepts a str, such as a Python standard library logger object from the logging module. If logger is not provided or is None, this method has no logging side effects.
  • label – An optional label which will be inserted into each line of logging output produced by this particular use of log
  • eager – An optional boolean which controls how the query result will be consumed. If True, the sequence will be consumed and logged in its entirety. If False (the default) the sequence will be evaluated and logged lazily as it consumed.

Warning

Use of eager=True requires use of sufficient memory to hold the entire sequence which is obviously not possible with infinite sequences. Use with care!

Returns:

A queryable over the unaltered source sequence.

Raises:
  • AttributeError - If logger does not support a debug() method.
  • ValueError - If the Queryable has been closed.

Examples

These examples log to a console logger called clog which can be created using the following incantation:

>>> import logging
>>> clog = logging.getLogger("clog")
>>> clog.setLevel(logging.DEBUG)
>>> clog.addHandler(logging.StreamHandler())

By default, log() uses deferred execution, so unless the output of log() is consumed nothing at all will be logged. In this example nothing is logged to the console because the result of log() is never consumed:

>>> numbers = [1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]
>>> query(numbers).log(clog)

We can easily consume the output of log() by chaining a call to to_list(). Use the default arguments for log():

>>> numbers = [1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]
>>> query(numbers).log(clog).to_list()
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : BEGIN (DEFERRED)
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [0] yields 1
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [1] yields 5
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [2] yields 9
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [3] yields 34
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [4] yields 2
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [5] yields 9
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [6] yields 12
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [7] yields 7
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [8] yields 13
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [9] yields 48
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [10] yields 34
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [11] yields 23
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [12] yields 34
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [13] yields 9
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : [14] yields 47
Queryable([1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]) : END (DEFERRED)
[1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]

The beginning and end of the sequence are delimited by BEGIN and END markers which also indicated whether logging is DEFERRED so items are logged only as they are requested or EAGER where the whole sequence will be returns immediately.

From left to right the log output shows:

  1. A label, which defaults to the repr() of the Queryable instance being logged.
  2. In square brackets the zero-based index of the element being logged.
  3. yields <element> showing the element value

Specify a label a more concise label to log():

>>> numbers = [1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]
>>> query(numbers).log(clog, label='query()').to_list()
query() : BEGIN (DEFERRED)
query() : [0] yields 1
query() : [1] yields 5
query() : [2] yields 9
query() : [3] yields 34
query() : [4] yields 2
query() : [5] yields 9
query() : [6] yields 12
query() : [7] yields 7
query() : [8] yields 13
query() : [9] yields 48
query() : [10] yields 34
query() : [11] yields 23
query() : [12] yields 34
query() : [13] yields 9
query() : [14] yields 47
query() : END (DEFERRED)
[1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]

We can show how the default deferred logging produces only required elements by only consuming the first three elements:

>>> numbers = [1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]
>>> query(numbers).log(clog, label='query()').take(3).to_list()
query() : BEGIN (DEFERRED)
query() : [0] yields 1
query() : [1] yields 5
query() : [2] yields 9
[1, 5, 9]

However, by setting the eager argument to be True, we can force logging of the whole sequence immediately:

>>> numbers = [1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]
>>> query(numbers).log(clog, label='query()', eager=True).take(3).to_list()
query() : BEGIN (EAGER)
query() : [0] = 1
query() : [1] = 5
query() : [2] = 9
query() : [3] = 34
query() : [4] = 2
query() : [5] = 9
query() : [6] = 12
query() : [7] = 7
query() : [8] = 13
query() : [9] = 48
query() : [10] = 34
query() : [11] = 23
query() : [12] = 34
query() : [13] = 9
query() : [14] = 47
query() : END (EAGER)
[1, 5, 9]

Note that in these cases the output has a different format and that use of eager logging in no way affects the query result.

If logger is None (or omitted), then logging is disabled completely:

>>> query(numbers).log(logger=None, label='query()').take(3).to_list()
[1, 5, 9]

Finally, see that log() can be used at multiple points within a query expression:

>>> numbers = [1, 5, 9, 34, 2, 9, 12, 7, 13, 48, 34, 23, 34, 9, 47]
>>> query(numbers).log(clog, label='query(numbers)')                   \
...        .select(lambda x: x * x).log(clog, label='squared')     \
...        .where(lambda x: x > 1000).log(clog, label="over 1000") \
...        .take(3).log(clog, label="take 3")                      \
...        .to_list()
take 3 : BEGIN (DEFERRED)
over 1000 : BEGIN (DEFERRED)
squared : BEGIN (DEFERRED)
query(numbers) : BEGIN (DEFERRED)
query(numbers) : [0] yields 1
squared : [0] yields 1
query(numbers) : [1] yields 5
squared : [1] yields 25
query(numbers) : [2] yields 9
squared : [2] yields 81
query(numbers) : [3] yields 34
squared : [3] yields 1156
over 1000 : [0] yields 1156
take 3 : [0] yields 1156
query(numbers) : [4] yields 2
squared : [4] yields 4
query(numbers) : [5] yields 9
squared : [5] yields 81
query(numbers) : [6] yields 12
squared : [6] yields 144
query(numbers) : [7] yields 7
squared : [7] yields 49
query(numbers) : [8] yields 13
squared : [8] yields 169
query(numbers) : [9] yields 48
squared : [9] yields 2304
over 1000 : [1] yields 2304
take 3 : [1] yields 2304
query(numbers) : [10] yields 34
squared : [10] yields 1156
over 1000 : [2] yields 1156
take 3 : [2] yields 1156
take 3 : END (DEFERRED)
[1156, 2304, 1156]
max(selector=identity)

Return the maximum value in a sequence.

All of the source sequence will be consumed.

Note

This method uses immediate execution.

Parameters:

selector – An optional single argument function which will be used to project the elements of the sequence. If omitted, the identity function is used.

Returns:

The maximum value of the projected sequence.

Raises:
  • ValueError - If the Queryable has been closed.
  • ValueError - If the sequence is empty.

Examples

Return the maximum value from a list of numbers:

>>> numbers = [1, -45, 23, -34, 19]
>>> query(numbers).max()
23

Return the maximum absolute value from a list of numbers:

>>> numbers = [1, -45, 23, -34, 19]
>>> query(numbers).max(abs)
45
min(selector=identity)

Return the minimum value in a sequence.

All of the source sequence will be consumed.

Note

This method uses immediate execution.

Parameters:

selector – An optional single argument function which will be used to project the elements of the sequence. If omitted, the identity function is used.

Returns:

The minimum value of the projected sequence.

Raises:
  • ValueError - If the Queryable has been closed.
  • ValueError - If the sequence is empty.

Examples

Return the minimum value from a list of numbers:

>>> numbers = [1, -45, 23, -34, 19]
>>> query(numbers).max()
-45

Return the minimum absolute value from a list of numbers:

>>> numbers = [1, -45, 23, -34, 19]
>>> query(numbers).max(abs)
1
of_type(classinfo)

Filters elements according to whether they are of a certain type.

Note

This method uses deferred execution.

Parameters:

classinfo – If classinfo is neither a class object nor a type object it may be a tuple of class or type objects, or may recursively contain other such tuples (other sequence types are not accepted).

Returns:

A Queryable over those elements of the source sequence for which the predicate is True.

Raises:
  • ValueError - If the Queryable is closed.
  • TypeError - If classinfo is not a class, type, or tuple of classes,
    types, and such tuples.

Examples

Return all of the strings from a list:

>>> numbers = ["one", 2.0, "three", "four", 5, 6.0, "seven", 8, "nine", "ten"]
>>> query(numbers).of_type(int).to_list()
[5, 8]

Return all the integers and floats from a list:

>>> numbers = ["one", 2.0, "three", "four", 5, 6.0, "seven", 8, "nine", "ten"]
>>> query(numbers).of_type((int, float)).to_list()
[2.0, 5, 6.0, 8]
order_by(key_selector=identity)

Sorts by a key in ascending order.

Introduces a primary sorting order to the sequence. Additional sort criteria should be specified by subsequent calls to then_by() and then_by_descending(). Calling order_by() or order_by_descending() on the results of a call to order_by() will introduce a new primary ordering which will override any already established ordering.

This method performs a stable sort. The order of two elements with the same key will be preserved.

Note

This method uses deferred execution.

Parameters:

key_selector – A unary function which extracts a key from each element using which the result will be ordered.

Returns:

An OrderedQueryable over the sorted elements.

Raises:
  • ValueError - If the Queryable is closed.
  • TypeError - If the key_selector is not callable.

Examples

Sort a list of numbers in ascending order by their own value:

>>> numbers = [1, -45, 23, -34, 19, 78, -23, 12, 98, -14]
>>> query(numbers).order_by().to_list()
[-45, -34, -23, -14, 1, 12, 19, 23, 78, 98]

Sort a list of numbers in ascending order by their absolute value:

>>> numbers = [1, -45, 23, -34, 19, 78, -23, 12, 98, -14]
>>> query(numbers).order_by(abs).to_list()
[1, 12, -14, 19, 23, -23, -34, -45, 78, 98]

See that the relative order of the two elements which compare equal (23 and -23 in the list shown) are preserved; the sort is stable.

order_by_descending(key_selector=identity)

Sorts by a key in descending order.

Introduces a primary sorting order to the sequence. Additional sort criteria should be specified by subsequent calls to then_by() and then_by_descending(). Calling order_by() or order_by_descending() on the results of a call to order_by() will introduce a new primary ordering which will override any already established ordering.

This method performs a stable sort. The order of two elements with the same key will be preserved.

Note

This method uses deferred execution.

Parameters:

key_selector – A unary function which extracts a key from each element using which the result will be ordered.

Returns:

An OrderedQueryable over the sorted elements.

Raises:
  • ValueError - If the Queryable is closed.
  • TypeError - If the key_selector is not callable.

Examples

Sort a list of numbers in ascending order by their own value:

>>> numbers = [1, -45, 23, -34, 19, 78, -23, 12, 98, -14]
>>> query(numbers).order_by_descending().to_list()
[98, 78, 23, 19, 12, 1, -14, -23, -34, -45]

Sort a list of numbers in ascending order by their absolute value:

>>> numbers = [1, -45, 23, -34, 19, 78, -23, 12, 98, -14]
>>> query(numbers).order_by_descending(abs).to_list()
[98, 78, -45, -34, 23, -23, 19, -14, 12, 1]

See that the relative order of the two elements which compare equal (23 and -23 in the list shown) are preserved; the sort is stable.

select(selector)

Transforms each element of a sequence into a new form.

Each element of the source is transformed through a selector function to produce a corresponding element in teh result sequence.

If the selector is identity the method will return self.

Note

This method uses deferred execution.

Parameters:

selector – A unary function mapping a value in the source sequence to the corresponding value in the generated generated sequence. The single positional argument to the selector function is the element value. The return value of the selector function should be the corresponding element of the result sequence.

Returns:

A Queryable over generated sequence whose elements are the result of invoking the selector function on each element of the source sequence.

Raises:
  • ValueError - If this Queryable has been closed.
  • TypeError - If selector is not callable.

Examples

Select the scores from a collection of student records:

>>> students = [dict(name="Joe Bloggs", score=54),
...             dict(name="Ola Nordmann", score=61),
...             dict(name="John Doe", score=51),
...             dict(name="Tom Cobleigh", score=71)]
>>> query(students).select(lambda student: student['score']).to_list()
[54, 61, 51, 71]

Transform a sequence of numbers into it square roots:

>>> import math
>>> numbers = [1, 45, 23, 34, 19, 78, 23, 12, 98, 14]
>>> query(numbers).select(math.sqrt).to_list()
[1.0, 6.708203932499369, 4.795831523312719, 5.830951894845301,
 4.358898943540674, 8.831760866327848, 4.795831523312719,
 3.4641016151377544, 9.899494936611665, 3.7416573867739413]
select_many(collection_selector=identity, result_selector=identity)

Projects each element of a sequence to an intermediate new sequence, flattens the resulting sequences into one sequence and optionally transforms the flattened sequence using a selector function.

Note

This method uses deferred execution.

Parameters:
  • collection_selector – A unary function mapping each element of the source iterable into an intermediate sequence. The single argument of the collection_selector is the value of an element from the source sequence. The return value should be an iterable derived from that element value. The default collection_selector, which is the identity function, assumes that each element of the source sequence is itself iterable.
  • result_selector – An optional unary function mapping the elements in the flattened intermediate sequence to corresponding elements of the result sequence. The single argument of the result_selector is the value of an element from the flattened intermediate sequence. The return value should be the corresponding value in the result sequence. The default result_selector is the identity function.
Returns:

A Queryable over a generated sequence whose elements are the result of applying the one-to-many collection_selector to each element of the source sequence, concatenating the results into an intermediate sequence, and then mapping each of those elements through the result_selector into the result sequence.

Raises:
  • ValueError - If this Queryable has been closed.
  • TypeError - If either collection_selector or result_selector are not
    callable.

Examples

Select all the words from three sentences by splitting each sentence into its component words:

>>> a = "The quick brown fox jumped over the lazy dog"
>>> b = "Pack my box with five dozen liquor jugs"
>>> c = "Jackdaws love my big sphinx of quartz"
>>> sentences = [a, b, c]
>>> query(sentences).select_many(lambda sentence: sentence.split()).to_list()
['The', 'quick', 'brown', 'fox', 'jumped', 'over', 'the', 'lazy',
 'dog', 'Pack', 'my', 'box', 'with', 'five', 'dozen', 'liquor',
 'jugs', 'Jackdaws', 'love', 'my', 'big', 'sphinx', 'of', 'quartz']

Select all the words from three sentences and return a list of the length of each word:

>>> a = "The quick brown fox jumped over the lazy dog"
>>> b = "Pack my box with five dozen liquor jugs"
>>> c = "Jackdaws love my big sphinx of quartz"
>>> sentences = [a, b, c]
>>> query(sentences).select_many(lambda sentence: sentence.split(), len).to_list()
[3, 5, 5, 3, 6, 4, 3, 4, 3, 4, 2, 3, 4, 4, 5, 6, 4, 8, 4, 2, 3, 6,
 2, 6]
select_many_with_correspondence(collection_selector=identity, result_selector=lambda source_element, collection_element: (source_element, collection_element)))

Projects each element of a sequence to an intermediate new sequence, and flattens the resulting sequence, into one sequence and uses a selector function to incorporate the corresponding source for each item in the result sequence.

Note

This method uses deferred execution.

Parameters:
  • collection_selector – A unary function mapping each element of the source iterable into an intermediate sequence. The single argument of the collection_selector is the value of an element from the source sequence. The return value should be an iterable derived from that element value. The default collection_selector, which is the identity function, assumes that each element of the source sequence is itself iterable.
  • result_selector – An optional binary function mapping the elements in the flattened intermediate sequence together with their corresponding source elements to elements of the result sequence. The two positional arguments of the result_selector are, first the source element corresponding to an element from the intermediate sequence, and second the actual element from the intermediate sequence. The return value should be the corresponding value in the result sequence. If no result_selector function is provided, the elements of the result sequence are KeyedElement namedtuples.
Returns:

A Queryable over a generated sequence whose elements are the result of applying the one-to-many collection_selector to each element of the source sequence, concatenating the results into an intermediate sequence, and then mapping each of those elements through the result_selector which incorporates the corresponding source element into the result sequence.

Raises:
  • ValueError - If this Queryable has been closed.
  • TypeError - If projector or selector are not callable.

Example

Incorporate each album track with its performing artist into a descriptive string:

>>> albums = [dict(name="Hotel California", artist="The Eagles",
...                tracks=["Hotel California",
...                        "New Kid in Town",
...                        "Life in the Fast Lane",
...                        "Wasted Time"]),
...           dict(name="Revolver", artist="The Beatles",
...                tracks=["Taxman",
...                        "Eleanor Rigby",
...                        "Yellow Submarine",
...                        "Doctor Robert"]),
...           dict(name="Thriller", artist="Michael Jackson",
...                tracks=["Thriller",
...                        "Beat It",
...                        "Billie Jean",
...                        "The Girl Is Mine"])]
>>> query(albums).select_many_with_correspondence(lambda album: album['tracks'],
...   lambda album, track: track + " by " + album['artist']).to_list()
['Hotel California by The Eagles', 'New Kid in Town by The Eagles',
 'Life in the Fast Lane by The Eagles', 'Wasted Time by The Eagles',
 'Taxman by The Beatles', 'Eleanor Rigby by The Beatles',
 'Yellow Submarine by The Beatles', 'Doctor Robert by The Beatles',
 'Thriller by Michael Jackson', 'Beat It by Michael Jackson',
 'Billie Jean by Michael Jackson',
 'The Girl Is Mine by Michael Jackson']
select_many_with_index(collection_selector=IndexedElement, result_selector=lambda source_element, collection_element: collection_element)

Projects each element of a sequence to an intermediate new sequence, incorporating the index of the element, flattens the resulting sequence into one sequence and optionally transforms the flattened sequence using a selector function.

Note

This method uses deferred execution.

Parameters:
  • collection_selector – A binary function mapping each element of the source sequence into an intermediate sequence, by incorporating its index in the source sequence. The two positional arguments to the function are the zero-based index of the source element and the value of the element. The result of the function should be an iterable derived from the index and element value. If no collection_selector is provided, the elements of the intermediate sequence will consist of tuples of (index, element) from the source sequence.
  • result_selector – An optional binary function mapping the elements in the flattened intermediate sequence together with their corresponding source elements to elements of the result sequence. The two positional arguments of the result_selector are, first the source element corresponding to an element from the intermediate sequence, and second the actual element from the intermediate sequence. The return value should be the corresponding value in the result sequence. If no result_selector function is provided, the elements of the flattened intermediate sequence are returned untransformed.
Returns:

A Queryable over a generated sequence whose elements are the result of applying the one-to-many collection_selector to each element of the source sequence which incorporates both the index and value of the source element, concatenating the results into an intermediate sequence, and then mapping each of those elements through the result_selector into the result sequence.

Raises:
  • ValueError - If this Queryable has been closed.
  • TypeError - If projector [and selector] are not callable.

Example

Incorporate the index of each album along with the track and artist for a digital jukebox. A generator expression is used to combine the index with the track name when generating the intermediate sequences from each album which will be concatenated into the final result:

>>> albums = [dict(name="Hotel California", artist="The Eagles",
...                tracks=["Hotel California",
...                        "New Kid in Town",
...                        "Life in the Fast Lane",
...                        "Wasted Time"]),
...           dict(name="Revolver", artist="The Beatles",
...                tracks=["Taxman",
...                        "Eleanor Rigby",
...                        "Yellow Submarine",
...                        "Doctor Robert"]),
...           dict(name="Thriller", artist="Michael Jackson",
...                tracks=["Thriller",
...                        "Beat It",
...                        "Billie Jean",
...                        "The Girl Is Mine"])]
>>> query(albums).select_many_with_index(lambda index, album: (str(index) + ' - ' + track for track in album['tracks'])).to_list()
['0 - Hotel California', '0 - New Kid in Town',
 '0 - Life in the Fast Lane', '0 - Wasted Time', '1 - Taxman',
 '1 - Eleanor Rigby', '1 - Yellow Submarine', '1 - Doctor Robert',
 '2 - Thriller', '2 - Beat It', '2 - Billie Jean',
 '2 - The Girl Is Mine']

Incorporate the index of each album along with the track and artist for a digital jukebox. A generator expression defining the collection_selector is used to combine the index with the track name when generating the intermediate sequences from each album which will be concatenated into the final result:

>>> albums = [dict(name="Hotel California", artist="The Eagles",
...                tracks=["Hotel California",
...                        "New Kid in Town",
...                        "Life in the Fast Lane",
...                        "Wasted Time"]),
...           dict(name="Revolver", artist="The Beatles",
...                tracks=["Taxman",
...                        "Eleanor Rigby",
...                        "Yellow Submarine",
...                        "Doctor Robert"]),
...           dict(name="Thriller", artist="Michael Jackson",
...                tracks=["Thriller",
...                        "Beat It",
...                        "Billie Jean",
...                        "The Girl Is Mine"])]
>>> query(albums).select_many_with_index(collection_selector=lambda index, album: (str(index) + ' - ' + track for track in album['tracks']),
...     result_selector=lambda album, track: album['name'] + ' - ' + track).to_list()
['Hotel California - 0 - Hotel California',
 'Hotel California - 0 - New Kid in Town',
 'Hotel California - 0 - Life in the Fast Lane',
 'Hotel California - 0 - Wasted Time', 'Revolver - 1 - Taxman',
 'Revolver - 1 - Eleanor Rigby', 'Revolver - 1 - Yellow Submarine',
 'Revolver - 1 - Doctor Robert', 'Thriller - 2 - Thriller',
 'Thriller - 2 - Beat It', 'Thriller - 2 - Billie Jean',
 'Thriller - 2 - The Girl Is Mine']
select_with_correspondence(transform, selector=KeyedElement)

Apply a callable to each element in an input sequence, generating a new sequence of 2-tuples where the first element is the input value and the second is the transformed input value.

The generated sequence is lazily evaluated.

Note

This method uses deferred execution.

Parameters:
  • selector – A unary function mapping a value in the source sequence to the second argument of the result selector.
  • result_selector – A binary callable mapping the of a value in the source sequence and the transformed value to the corresponding value in the generated sequence. The two positional arguments of the selector function are the original source element and the transformed value. The return value should be the corresponding value in the result sequence. The default selector produces a KeyedElement containing the index and the element giving this function similar behaviour to the built-in enumerate().
Returns:

When using the default selector, a Queryable whose elements are KeyedElements where the first element is from the input sequence and the second is the result of invoking the transform function on the first value.

Raises:
  • ValueError - If this Queryable has been closed.
  • TypeError - If transform is not callable.

Examples

Generate a list of KeyedElement items using the default selector:

>>> query(range(10)).select_with_correspondence(lambda x: x%5).to_list()
[KeyedElement(key=0, value=0),
 KeyedElement(key=1, value=1),
 KeyedElement(key=2, value=2),
 KeyedElement(key=3, value=3),
 KeyedElement(key=4, value=4),
 KeyedElement(key=5, value=0),
 KeyedElement(key=6, value=1),
 KeyedElement(key=7, value=2),
 KeyedElement(key=8, value=3),
 KeyedElement(key=9, value=4)]

Square the integers zero to nine, retaining only those elements for which the square is an odd number:

 >>> query(range(10))                           \
 ... .select_with_correspondence(lambda x: x*x) \
 ... .where(lambda y: y.value%2 != 0)           \
 ... .select(lambda y: y.key)                   \
 ... .to_list()
 ...
[1, 3, 5, 7, 9]
select_with_index(selector=IndexedElement)

Transforms each element of a sequence into a new form, incorporating the index of the element.

Each element is transformed through a selector function which accepts the element value and its zero-based index in the source sequence. The generated sequence is lazily evaluated.

Note

This method uses deferred execution.

Parameters:

selector – A binary function mapping the index of a value in the source sequence and the element value itself to the corresponding value in the generated sequence. The two positional arguments of the selector function are the zero- based index of the current element and the value of the current element. The return value should be the corresponding value in the result sequence. The default selector produces an IndexedElement containing the index and the element giving this function similar behaviour to the built-in enumerate().

Returns:

A Queryable whose elements are the result of invoking the selector function on each element of the source sequence

Raises:
  • ValueError - If this Queryable has been closed.
  • TypeError - If selector is not callable.

Examples

Generate a list of IndexedElement items using the default selector. The contents of an IndexedElement can either be accessed using the named attributes, or through the zero (index) and one (element) indexes:

>>> dark_side_of_the_moon = [ 'Speak to Me', 'Breathe', 'On the Run',
... 'Time', 'The Great Gig in the Sky', 'Money', 'Us and Them',
... 'Any Colour You Like', 'Brain Damage', 'Eclipse']
>>> query(dark_side_of_the_moon).select_with_index().to_list()
[IndexedElement(index=0, element='Speak to Me'),
 IndexedElement(index=1, element='Breathe'),
 IndexedElement(index=2, element='On the Run'),
 IndexedElement(index=3, element='Time'),
 IndexedElement(index=4, element='The Great Gig in the Sky'),
 IndexedElement(index=5, element='Money'),
 IndexedElement(index=6, element='Us and Them'),
 IndexedElement(index=7, element='Any Colour You Like'),
 IndexedElement(index=8, element='Brain Damage'),
 IndexedElement(index=9, element='Eclipse')]

Generate numbered album tracks using a custom selector:

>>> query(dark_side_of_the_moon).select_with_index(lambda index, track: str(index) + '. ' + track).to_list()
['0. Speak to Me', '1. Breathe', '2. On the Run', '3. Time',
 '4. The Great Gig in the Sky', '5. Money', '6. Us and Them',
 '7. Any Colour You Like', '8. Brain Damage', '9. Eclipse']
sequence_equal(second_iterable, equality_comparer=operator.eq)

Determine whether two sequences are equal by elementwise comparison.

Sequence equality is defined as the two sequences being equal length and corresponding elements being equal as determined by the equality comparer.

Note

This method uses immediate execution.

Parameters:
  • second_iterable – The sequence which will be compared with the source sequence.
  • equality_comparer – An optional binary predicate function which is used to compare corresponding elements. Should return True if the elements are equal, otherwise False. The default equality comparer is operator.eq which calls __eq__ on elements of the source sequence with the corresponding element of the second sequence as a parameter.
Returns:

True if the sequences are equal, otherwise False.

Raises:
  • ValueError - If the Queryable is closed.
  • TypeError - If second_iterable is not in fact iterable.
  • TypeError - If equality_comparer is not callable.

Examples

Determine whether lists a and b are equal:

>>> a = [1, 3, 6, 2, 8]
>>> b = [3, 6, 2, 1, 8]
>>> query(a).sequence_equal(b)
False

Determine whether lists a and b and equal when absolute values are compared:

>>> a = [1, -3, 6, -2, 8]
>>> b = [-1, 3, -6, 2, -8]
>>> query(a).sequence_equal(b, lambda lhs, rhs: abs(lhs) == abs(rhs))
True
single(predicate=None)

The only element (which satisfies a condition).

If the predicate is omitted or is None this query returns the only element in the sequence; otherwise, it returns the only element in the sequence for which the predicate evaluates to True. Exceptions are raised if there is either no such element or more than one such element.

Note

This method uses immediate execution.

Parameters:

predicate – An optional unary predicate function, the only argument to which is the element. The return value should be True for matching elements, otherwise False. If the predicate is omitted or None the only element of the source sequence will be returned.

Returns:

The only element of the sequence if predicate is None, otherwise the only element for which the predicate returns True.

Raises:
  • ValueError - If the Queryable is closed.
  • ValueError - If, when predicate is None the source sequence contains
    more than one element.
  • ValueError - If there are no elements matching the predicate or more
    then one element matching the predicate.
  • TypeError - If the predicate is not callable.

Examples

Return the only element in the sequence:

>>> a = [5]
>>> query(a).single()
5

Attempt to get the single element from a sequence with multiple elements:

>>> a = [7, 5, 4]
>>> query(a).single()
ValueError: Sequence for single() contains multiple elements.

Return the only element in a sequence meeting a condition:

>>> a = [7, 5, 4]
>>> query(a).single(lambda x: x > 6)
7

Attempt to get the single element from a sequence which meets a condition when in fact multiple elements do so:

>>> a = [7, 5, 4]
>>> query(a).single(lambda x: x >= 5)
ValueError: Sequence contains more than one value matching single()
predicate.
single_or_default(default, predicate=None)

The only element (which satisfies a condition) or a default.

If the predicate is omitted or is None this query returns the only element in the sequence; otherwise, it returns the only element in the sequence for which the predicate evaluates to True. A default value is returned if there is no such element. An exception is raised if there is more than one such element.

Note

This method uses immediate execution.

Parameters:
  • default – The value which will be returned if either the sequence is empty or there are no elements matching the predicate.
  • predicate – An optional unary predicate function, the only argument to which is the element. The return value should be True for matching elements, otherwise False. If the predicate is omitted or None the only element of the source sequence will be returned.
Returns:

The only element of the sequence if predicate is None, otherwise the only element for which the predicate returns True. If there are no such elements the default value will returned.

Raises:
  • ValueError - If the Queryable is closed.
  • ValueError - If, when predicate is None the source sequence contains
    more than one element.
  • ValueError - If there is more then one element matching the
    predicate.
  • TypeError - If the predicate is not callable.

Examples

Return the only element in the sequence:

>>> a = [5]
>>> query(a).single_or_default(7)
5

Attempt to get the single element from a sequence with multiple elements:

>>> a = [7, 5, 4]
>>> query(a).single_or_default(9)
ValueError: Sequence for single_or_default() contains multiple
elements

Attempt to get the single element from a sequence with no elements:

>>> a = []
>>> query(a).single_or_default(9)
9

Return the only element in a sequence meeting a condition:

>>> a = [7, 5, 4]
>>> query(a).single_or_default(9, lambda x: x > 6)
7

Attempt to get the single element from a sequence which meets a condition when in fact multiple elements do so:

>>> a = [7, 5, 4]
>>> query(a).single(lambda x: x >= 5)
ValueError: Sequence contains more than one value matching
single_or_default() predicate.

Attempt to get the single element matching a predicate from a sequence which contains no matching elements:

>>> a = [7, 5, 4]
>>> query(a).single_or_default(9, lambda x: x > 20)
9
skip(count=1)

Skip the first count contiguous elements of the source sequence.

If the source sequence contains fewer than count elements returns an empty sequence and does not raise an exception.

Note

This method uses deferred execution.

Parameters:count – The number of elements to skip from the beginning of the sequence. If omitted defaults to one. If count is less than one the result sequence will be empty.
Returns:A Queryable over the elements of source excluding the first count elements.
Raises:ValueError - If the Queryable is closed().

Examples

Skip the first element of a sequence:

>>> a = [7, 5, 4]
>>> query(a).skip().to_list()
[5, 4]

Skip the first two elements of a sequence:

>>> a = [7, 5, 4]
>>> query(a).skip(2).to_list()
[4]
skip_while(predicate)

Omit elements from the start for which a predicate is True.

Note

This method uses deferred execution.

Parameters:

predicate – A single argument predicate function.

Returns:

A Queryable over the sequence of elements beginning with the first element for which the predicate returns False.

Raises:
  • ValueError - If the Queryable is closed().
  • TypeError - If predicate is not callable.

Example

Skip while elements start with the letter ‘a’:

>>> words = ['aardvark', 'antelope', 'ape', 'baboon', 'cat',
...          'anaconda', 'zebra']
>>> query(words).skip_while(lambda s: s.startswith('a')).to_list()
['baboon', 'cat', 'anaconda', 'zebra']
sum(selector=identity)

Return the arithmetic sum of the values in the sequence..

All of the source sequence will be consumed.

Note

This method uses immediate execution.

Parameters:selector – An optional single argument function which will be used to project the elements of the sequence. If omitted, the identity function is used.
Returns:The total value of the projected sequence, or zero for an empty sequence.
Raises:ValueError - If the Queryable has been closed.

Examples

Compute the sum of a sequence of floats:

>>> numbers = [5.6, 3.4, 2.3, 9.3, 1.7, 2.4]
>>> query(numbers).sum()
24.7

Compute the sum of the squares of a sequence of integers:

>>> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> query(numbers).sum(lambda x: x*x)
385
take(count=1)

Returns a specified number of elements from the start of a sequence.

If the source sequence contains fewer elements than requested only the available elements will be returned and no exception will be raised.

Note

This method uses deferred execution.

Parameters:count – An optional number of elements to take. The default is one.
Returns:A Queryable over the first count elements of the source sequence, or the all elements of elements in the source, whichever is fewer.
Raises:ValueError - If the Queryable is closed()

Examples

Take one element from the start of a list:

>>> a = [9, 7, 3, 4, 2]
>>> query(a).take().to_list()
[9]

Take three elements from the start of a list:

>>> query(a).take(3).to_list()
[9, 7, 3]
take_while(predicate)

Returns elements from the start while the predicate is True.

Note

This method uses deferred execution.

Parameters:

predicate – A function returning True or False with which elements will be tested.

Returns:

A Queryable over the elements from the beginning of the source sequence for which predicate is True.

Raises:
  • ValueError - If the Queryable is closed()
  • TypeError - If the predicate is not callable.

Example

>>> words = ['aardvark', 'antelope', 'ape', 'baboon', 'cat',
...          'anaconda', 'zebra']
>>> query(words).take_while(lambda s: s.startswith('a')).to_list()
['aardvark', 'antelope', 'ape']
to_dictionary(key_selector=identity, value_selector=identity)

Build a dictionary from the source sequence.

Parameters:
  • key_selector – A unary callable to extract a key from each item. By default the key is the item itself.
  • value_selector – A unary callable to extract a value from each item. By default the value is the item itself.

Note

This method uses immediate execution.

Raises:
  • ValueError - If the Queryable is closed.
  • TypeError - If key_selector is not callable.
  • TypeError - If value_selector is not callable.

Examples

Convert to a dictionary using the default key and value selectors:

>>> animals = ['aardvark', 'baboon', 'cat', 'dot', 'frog', 'giraffe',
...            'horse', 'iguana']
>>> query(animals).to_dictionary()
{'horse': 'horse', 'aardvark': 'aardvark', 'frog': 'frog', 'cat':
 'cat', 'giraffe': 'giraffe', 'baboon': 'baboon', 'dot': 'dot',
 'iguana': 'iguana'}

Convert to a dictionary extracting the first letter as a key:

>>> animals = ['aardvark', 'baboon', 'cat', 'dot', 'frog', 'giraffe',
...            'horse', 'iguana']
>>> query(animals).to_dictionary(key_selector=lambda x: x[0])
{'a': 'aardvark', 'c': 'cat', 'b': 'baboon', 'd': 'dot', 'g':
 'giraffe', 'f': 'frog', 'i': 'iguana', 'h': 'horse'}

Convert to a dictionary extracting the first letter as a key and converting the value to uppercase:

>>> query(animals).to_dictionary(key_selector=lambda x: x[0],
...                            value_selector=lambda x: x.upper())
{'a': 'AARDVARK', 'c': 'CAT', 'b': 'BABOON', 'd': 'DOT', 'g':
 'GIRAFFE', 'f': 'FROG', 'i': 'IGUANA', 'h': 'HORSE'}

Attempt to convert a list of fruit to a dictionary using the initial letter as the key, in the presence of a multiple keys of the same value:

>>> fruit = ['apple', 'apricot', 'banana', 'cherry']
>>> query(fruit).to_dictionary(lambda f: f[0])
ValueError: Duplicate key value 'a' in sequence during
to_dictionary()
to_list()

Convert the source sequence to a list.

Note

This method uses immediate execution.

Example

Convert from a tuple into a list:

>>> a = (1, 6, 8, 3, 4)
>>> query(a).to_list()
[1, 6, 8, 3, 4]
to_lookup()

Returns a Lookup object, using the provided selector to generate a key for each item.

Note

This method uses immediate execution.

Examples

Convert to a Lookup using the default key_selector and value_selector:

>>> countries = ['Austria', 'Bahrain', 'Canada', 'Algeria',
...              'Belgium', 'Croatia', 'Kuwait', 'Angola', 'Greece',
...              'Korea']
>>> query(countries).to_lookup()
Lookup([('Austria', 'Austria'), ('Bahrain', 'Bahrain'), ('Canada',
'Canada'), ('Algeria', 'Algeria'), ('Belgium', 'Belgium'),
('Croatia', 'Croatia'), ('Kuwait', 'Kuwait'), ('Angola', 'Angola'),
('Greece', 'Greece'), ('Korea', 'Korea')])

Convert to a Lookup, using the initial letter of each country name as the key:

>>> countries = ['Austria', 'Bahrain', 'Canada', 'Algeria',
...              'Belgium', 'Croatia', 'Kuwait', 'Angola', 'Greece',
...              'Korea']
>>> query(countries).to_lookup(key_selector=lambda name: name[0])
Lookup([('A', 'Austria'), ('A', 'Algeria'), ('A', 'Angola'), ('B',
'Bahrain'), ('B', 'Belgium'), ('C', 'Canada'), ('C', 'Croatia'),
('K', 'Kuwait'), ('K', 'Korea'), ('G', 'Greece')])

Convert to a Lookup, using the initial letter of each country name as the key and the upper case name as the value:

>>> countries = ['Austria', 'Bahrain', 'Canada', 'Algeria',
...              'Belgium', 'Croatia', 'Kuwait', 'Angola', 'Greece',
...              'Korea']
>>> query(countries).to_lookup(key_selector=lambda name: name[0],
...                        value_selector=lambda name: name.upper())
Lookup([('A', 'AUSTRIA'), ('A', 'ALGERIA'), ('A', 'ANGOLA'), ('B',
'BAHRAIN'), ('B', 'BELGIUM'), ('C', 'CANADA'), ('C', 'CROATIA'),
('K', 'KUWAIT'), ('K', 'KOREA'), ('G', 'GREECE')])
to_set()

Convert the source sequence to a set.

Note

This method uses immediate execution.

Raises:
  • ValueError - If duplicate keys are in the projected source sequence.
  • ValueError - If the Queryable is closed().

Examples

Convert a list to a set:

>>> a = [4, 9, 2, 3, 0, 1]
>>> query(a).to_set()
{0, 1, 2, 3, 4, 9}

Attempt to convert a list containing duplicates to a set:

>>> b = [6, 2, 9, 0, 2, 1, 9]
>>> query(b).to_set()
ValueError: Duplicate item value 2 in sequence during to_set()
to_str(separator)

Build a string from the source sequence.

The elements of the query result will each coerced to a string and then the resulting strings concatenated to return a single string. This allows the natural processing of character sequences as strings. An optional separator which will be inserted between each item may be specified.

Note

this method uses immediate execution.

Parameters:

separator – An optional separator which will be coerced to a string and inserted between each source item in the resulting string.

Returns:

A single string which is the result of stringifying each element and concatenating the results into a single string.

Raises:
  • TypeError - If any element cannot be coerced to a string.
  • TypeError - If the separator cannot be coerced to a string.
  • ValueError - If the Queryable is closed.

Examples

Convert a sequence of characters into a string:

>>> chars = ['c', 'h', 'a', 'r', 'a', 'c', 't', 'e', 'r', 's']
>>> query(chars).to_str()
'characters'

Concatenate some word fragments into a single string:

>>> syllables = ['pen', 'ta', 'syll', 'ab', 'ic']
>>> query(syllables).to_str()

Coerce some integers to strings and concatenate their digits to form a single string:

>>> codes = [72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33]
>>> query(codes).to_str('-')
'72-101-108-108-111-44-32-87-111-114-108-100-33'

Coerce some integers to strings and concatenate their values separated by hyphens to form a single string:

>>> codes = [72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33]
>>> query(codes).to_str('-')
'72-101-108-108-111-44-32-87-111-114-108-100-33'
to_tuple()

Convert the source sequence to a tuple.

Note

This method uses immediate execution.

Example

Convert from a list into a tuple:

>>> a = [1, 6, 8, 3, 4]
>>> query(a).to_list()
(1, 6, 8, 3, 4)
union(second_iterable, selector=identity)

Returns those elements which are either in the source sequence or in the second_iterable, or in both.

Note

This method uses deferred execution.

Parameters:
  • second_iterable – Elements from this sequence are returns if they are not also in the source sequence.
  • selector – An optional single argument function which is used to project the elements in the source and second_iterables prior to comparing them. If omitted the identity function will be used.
Returns:

A sequence containing all elements in the source sequence and second sequence.

Raises:
  • ValueError - If the Queryable has been closed.
  • TypeError - If the second_iterable is not in fact iterable.
  • TypeError - If the selector is not callable.

Examples

Create a list of numbers which are in either or both of two lists:

>>> a = [1, 6, 9, 3]
>>> b = [2, 6, 7, 3]
>>> query(a).union(b).to_list()
[1, 6, 9, 3, 2, 7]

Create a list of numbers, based on their absolute values, which are in either or both of list a or list b, preferentially taking numbers from list a where the absolute value is present in both:

>>> a = [-1, -4, 2, 6, 7]
>>> b = [3, -4, 2, -6, 9]
>>> query(a).union(b, abs).to_list()
[-1, -4, 2, 6, 7, 3, 9]
where(predicate)

Filters elements according to whether they match a predicate.

Note

This method uses deferred execution.

Parameters:

predicate – A unary function which is applied to each element in the source sequence. Source elements for which the predicate returns True will be present in the result.

Returns:

A Queryable over those elements of the source sequence for which the predicate is True.

Raises:
  • ValueError - If the Queryable is closed.
  • TypeError - If the predicate is not callable.

Example

Filter for elements greater than five:

>>> a = [1, 7, 2, 9, 3]
>>> query(a).where(lambda x: x > 5).to_list()
[7, 9]
zip(second_iterable, result_selector=lambda x, y: (x, y))

Elementwise combination of two sequences.

The source sequence and the second iterable are merged element-by- element using a function to combine them into the single corresponding element of the result sequence. The length of the result sequence is equal to the length of the shorter of the two input sequences.

Note

This method uses deferred execution.

Parameters:
  • second_iterable – The second sequence to be combined with the source sequence.
  • result_selector – An optional binary function for combining corresponding elements of the source sequences into an element of the result sequence. The first and second positional arguments are the elements from the source sequences. The result should be the result sequence element. If omitted, the result sequence will consist of 2-tuple pairs of corresponding elements from the source sequences.
Returns:

A Queryable over the merged elements.

Raises:
  • ValueError - If the Queryable is closed.
  • TypeError - If result_selector is not callable.

Examples

Combine two sequences using the default result selector which creates a 2-tuple pair of corresponding elements:

>>> a = [1, 4, 6, 4, 2, 9, 1, 3, 8]
>>> b = [6, 7, 2, 9, 3, 5, 9]
>>> query(a).zip(b).to_list()
[(1, 6), (4, 7), (6, 2), (4, 9), (2, 3), (9, 5), (1, 9)]

Multiply the corresponding elements of two sequences to create a new sequence equal in length to the shorter of the two:

>>> a = [1, 4, 6, 4, 2, 9, 1, 3, 8]
>>> b = [6, 7, 2, 9, 3, 5, 9]
>>> query(a).zip(b, lambda x, y: x * y).to_list()
[6, 28, 12, 36, 6, 45, 9]

asq.queryables.OrderedQueryable

class asq.queryables.OrderedQueryable(iterable, order, func)

A Queryable representing an ordered iterable.

The sorting implemented by this class is an incremental partial sort so you don’t pay for sorting results which are never enumerated.

TODO: Document OrderedQueryable

asq.queryables.Lookup

class asq.queryables.Lookup(key_value_pairs)

A multi-valued dictionary.

A Lookup represents a collection of keys, each one of which is mapped to one or more values. The keys in the Lookup are maintained in the order in which they were added. The values for each key are also maintained in order.

Note

Lookup objects are immutable.

All standard query operators may be used on a Lookup. When iterated or used as a Queryable the elements are returned as a sequence of Grouping objects.

Example

Lookup, being a subclass of Queryable supports all of the asq query operators over a collection of Groupings. For example, to select only those groups containing two or more elements and then flatten those groups into a single list, use:

 >>> key_value_pairs = [('tree', 'oak'),
 ...                    ('bird', 'eagle'),
 ...                    ('bird', 'swallow'),
 ...                    ('tree', 'birch'),
 ...                    ('mammal', 'mouse'),
 ...                    ('tree', 'poplar')]
 ...
 >>> lookup = Lookup(key_value_pairs)
 >>> lookup.where(lambda group: len(group) >= 2).select_many().to_list()
['oak', 'birch', 'poplar', 'eagle', 'swallow']
__init__(key_value_pairs)

Construct a Lookup with a sequence of (key, value) tuples.

Parameters:key_value_pairs – An iterable over 2-tuples each containing a key, value pair.

Example

To construct a Lookup from key value pairs:

>>> key_value_pairs = [('tree', 'oak'),
...                    ('bird', 'eagle'),
...                    ('bird', 'swallow'),
...                    ('tree', 'birch'),
...                    ('mammal', 'mouse'),
...                    ('tree', 'poplar')]
...
>>> lookup = Lookup(key_value_pairs)
__getitem__(key)
The sequence corresponding to a given key, or an empty sequence if there are no values corresponding to that key.
Parameters:key – The key of the group to be returned.
Returns:The Grouping corresponding to the supplied key.

Examples

To retrieve a Grouping for a given key:

>>> key_value_pairs = [('tree', 'oak'),
...                    ('bird', 'eagle'),
...                    ('bird', 'swallow'),
...                    ('tree', 'birch'),
...                    ('mammal', 'mouse'),
...                    ('tree', 'poplar')]
...
>>> lookup = Lookup(key_value_pairs)
>>> lookup['tree']
Grouping(key='tree')

but if no such key exists a Grouping will still be returned, albeit an empty one:

>>> vehicles = lookup['vehicle']
>>> vehicles
Grouping(key='vehicle')
>>> len(vehicles)
0
__len__()

Support for the len() built-in function.

Returns:The number of Groupings (keys) in the lookup.

Example

To determine the number of Groupings in a Lookup:

>>> key_value_pairs = [('tree', 'oak'),
...                    ('bird', 'eagle'),
...                    ('bird', 'swallow'),
...                    ('tree', 'birch'),
...                    ('mammal', 'mouse'),
...                    ('tree', 'poplar')]
>>> lookup = Lookup(key_value_pairs)
>>> len(lookup)
3
__contains__()

Support for the ‘in’ membership operator.

Parameters:key – The key for which membership will be tested.
Returns:True if the Lookup contains a Grouping for the specified key, otherwise False.

Example

To determine whether a Lookup contains a specific Grouping:

>>> key_value_pairs = [('tree', 'oak'),
...                    ('bird', 'eagle'),
...                    ('bird', 'swallow'),
...                    ('tree', 'birch'),
...                    ('mammal', 'mouse'),
...                    ('tree', 'poplar')]
>>> lookup = Lookup(key_value_pairs)
>>> 'tree' in lookup
True
>>> 'vehicle' in lookup
False
__repr__()

Support for the repr() built-in function.

Returns:The official string representation of the object.

Example

To produce a string representation of a Lookup:

>>> key_value_pairs = [('tree', 'oak'),
...                    ('bird', 'eagle'),
...                    ('bird', 'swallow'),
...                    ('tree', 'birch'),
...                    ('mammal', 'mouse'),
...                    ('tree', 'poplar')]
...
>>> lookup = Lookup(key_value_pairs)
>>> repr(lookup)
"Lookup([('tree', 'oak'), ('tree', 'birch'), ('tree', 'poplar'),
('bird', 'eagle'), ('bird', 'swallow'), ('mammal', 'mouse')])"
apply_result_selector(selector)

Example

Convert each group to a set using a lambda selector and put the resulting sets in a list:

>>> key_value_pairs = [('tree', 'oak'),
...                    ('bird', 'eagle'),
...                    ('bird', 'swallow'),
...                    ('tree', 'birch'),
...                    ('mammal', 'mouse'),
...
>>> lookup = Lookup(key_value_pairs)
>>> lookup.apply_result_selector(lambda key, group: set(group)).to_list()
[set(['poplar', 'oak', 'birch']), set(['eagle', 'swallow']),
set(['mouse'])]
to_dictionary(key_selector=None, value_selector=None)

Build a dictionary from the source sequence.

Parameters:
  • key_selector – A unary callable to extract a key from each item. By default the key of the Grouping.
  • value_selector – A unary callable to extract a value from each item. By default the value is the list of items from the Grouping.

Note

This method uses immediate execution.

Raises:
  • ValueError - If the Queryable is closed.
  • TypeError - If key_selector is not callable.
  • TypeError - If value_selector is not callable.

Example

Convert a Lookup to a dict using the default selectors which produce a dictionary mapping the lookup keys to lists:

>>> key_value_pairs = [('tree', 'oak'),
...                    ('bird', 'eagle'),
...                    ('bird', 'swallow'),
...                    ('tree', 'birch'),
...                    ('mammal', 'mouse'),
...
>>> lookup = Lookup(key_value_pairs)
>>> lookup.to_dictionary()
{'mammal': ['mouse'], 'bird': ['eagle', 'swallow'], 'tree': ['oak', 'birch']}

Providing a value_selector to construct the values of the dictionary as a set rather than the default list:

>>> lookup.to_dictionary(value_selector=set)
{'mammal': {'mouse'}, 'bird': {'swallow', 'eagle'}, 'tree': {'birch', 'oak'}}

asq.queryables.Grouping

class asq.queryables.Grouping(key, items)

A collection of objects which share a common key.

All standard query operators may be used on a Grouping.

Note

It is not intended that clients should directly create Grouping objects. Instances of this class are retrieved from Lookup objects.

Example

Grouping, being a subclass of Queryable, supports all of the asq query operators. For example, to produce a list of the group items in upper case:

>>> g = Grouping("fruit", ["pear", "apple", "orange", "banana"])
>>> g.select(str.upper).to_list()
['PEAR', 'APPLE', 'ORANGE', 'BANANA']
__init__(key, iterable)

Create a Grouping with a given key and a collection of members.

Parameters:
  • key – The key corresponding to this Grouping
  • items – An iterable collection of the members of the group.

Example

Construct a Grouping from a list:

>>> Grouping("fruit", ["pear", "apple", "orange", "banana"])
Grouping(key='fruit')
key

The key common to all elements.

Example

To retrieve the key from a Grouping:

>>> g = Grouping("fruit", ["pear", "apple", "orange", "banana"])
>>> g.key
'fruit'
__len__()

The number of items in the Grouping.

Example

To retrieve the number of items in a Grouping:

>>> g = Grouping("fruit", ["pear", "apple", "orange", "banana"])
>>> len(g)
4
__eq__()

Determine value equality with another grouping.

Parameters:rhs – The object on the right-hand-side of the comparison must support a property called ‘key’ and be iterable.
Returns:True if the keys and sequences are equal, otherwise False.

Example

To test whether two Groupings are equal in value:

>>> g1 = Grouping("fruit", ["pear", "apple", "orange", "banana"])
>>> g2 = Grouping("fruit", ["pear", "apple", "orange", "banana"])
>>> g1 == g2
True
__ne__()

Determine value inequality with another grouping.

Parameters:rhs – The object on the right-hand-side of the comparison must support a property called ‘key’ and be iterable.
Returns:True if the keys or sequences are not equal, otherwise False.

Example

To test whether two Groupings are inequal in value:

>>> g1 = Grouping("fruit", ["pear", "apple", "orange", "banana"])
>>> g2 = Grouping("fruit", ["cherry", "apple", "orange", "banana"])
>>> g1 != g2
True
__repr__()

Example

To create a string representation of the Grouping:

>>> g = Grouping("fruit", ["pear", "apple", "orange", "banana"])
>>> repr(g)
Grouping(key="fruit", items=["pear", "apple", "orange", "banana"])
to_dictionary(key_selector=None, value_selector=None)

Build a dictionary from the source sequence.

Parameters:
  • key_selector – A unary callable to extract a key from each item or None. If None, the default key selector produces a single dictionary key, which if the key of this Grouping.
  • value_selector – A unary callable to extract a value from each item. If None, the default value selector produces a list, which contains all elements from this Grouping.

Note

This method uses immediate execution.

Raises:
  • ValueError - If the Queryable is closed.
  • TypeError - If key_selector is not callable.
  • TypeError - If value_selector is not callable.

Examples

Convert a Grouping to a dict using the default selectors:

>>> g = Grouping("fruit", ["pear", "apple", "orange", "banana"])
>>> g.to_dictionary()
{'fruit': ['pear', 'apple', 'orange', 'banana']}

Providing a key_selector and to generate the dictionary keys from the length of each element in the Grouping:

>>> g.to_dictionary(key_selector=len, value_selector=identity)
{4: 'pear', 5: 'apple', 6: 'banana'}

Notice that first six-letter word ‘orange’ is overwritten by the second six-letter word, ‘banana’.

Since the key of the Grouping is not availble via the items in the collection, if you need to incorporate the key into the produced dict it must be incorporated into the selectors:

>>> g.to_dictionary(
...     key_selector=lambda item: '{} letter {}'.format(len(item), g.key),
...     value_selector=str.capitalize)
...
{'5 letter fruit': 'Apple', '6 letter fruit': 'Banana', '4 letter fruit': 'Pear'}