Skip to content

Commit

Permalink
finished implementing joins
Browse files Browse the repository at this point in the history
  • Loading branch information
EntilZha committed Mar 22, 2015
1 parent 714b5a3 commit 22367ff
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 1 deletion.
98 changes: 97 additions & 1 deletion functional/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ def __unicode__(self):
return unicode(self.sequence)

def __format__(self, formatstr):
"""
Format the sequence using formatstr and format()
:param formatstr: format passed to format()
:return: formatted string
"""
return format(self.sequence, formatstr)

def __nonzero__(self):
Expand Down Expand Up @@ -310,6 +316,18 @@ def drop(self, n):
"""
return FunctionalSequence(self.sequence[n:])

def drop_right(self, n):
"""
Drops the last n elements of the sequence.
>>> seq([1, 2, 3, 4]).drop_right(2)
[1, 2]
:param n: number of elements to drop
:return: sequence with last n elements dropped
"""
return FunctionalSequence(self.sequence[:n])

def drop_while(self, f):
"""
Drops elements in the sequence while f evaluates to True, then returns the rest.
Expand Down Expand Up @@ -857,7 +875,7 @@ def join(self, other):
[('a', (1, 2)), ('c', (3, 5))]
:param other: sequence to join with
:return: joined sequence of (K, (V, W)) pairs.
:return: joined sequence of (K, (V, W)) pairs
"""
seq_kv = self.to_dict()
other_kv = dict(other)
Expand All @@ -868,6 +886,84 @@ def join(self, other):
result[k] = (seq_kv[k], other_kv[k])
return FunctionalSequence(result.items())

def _general_join(self, other, join_type):
"""
Sequence and other must be composed of (Key, Value) pairs. If self.sequence contains (K, V) pairs and
other contains (K, W) pairs, the return result is a sequence of (K, (V, W)) pairs. If join_type is "left",
V values will always be present, W values may be present or None. If join_type is "right", W values will
always be present, W values may be present or None. If join_type is "outer", V or W may be present or None,
but never at the same time.
>>> seq([('a', 1), ('b', 2)])._general_join([('a', 3), ('c', 4)], "left")
[('a', (1, 3)), ('b', (2, None)]
>>> seq([('a', 1), ('b', 2)])._general_join([('a', 3), ('c', 4)], "right")
[('a', (1, 3)), ('c', (None, 4)]
>>> seq([('a', 1), ('b', 2)])._general_join([('a', 3), ('c', 4)], "outer")
[('a', (1, 3)), ('b', (2, None)), ('c', (None, 4))]
:param other: sequence to join with
:param join_type: specifies join_type, may be "left", "right", or "outer"
:return: side joined sequence of (K, (V, W)) pairs
"""
seq_kv = self.to_dict()
other_kv = dict(other)
if join_type == "left":
keys = seq_kv.keys()
elif join_type == "right":
keys = other_kv.keys()
elif join_type == "outer":
keys = set(list(seq_kv.keys()) + list(other_kv.keys()))
else:
raise TypeError("Wrong type of join specified")
result = {}
for k in keys:
result[k] = (seq_kv.get(k), other_kv.get(k))
return FunctionalSequence(result.items())

def left_join(self, other):
"""
Sequence and other must be composed of (Key, Value) pairs. If self.sequence contains (K, V) pairs and
other contains (K, W) pairs, the return result is a sequence of (K, (V, W)) pairs. V values will always be
present, W values may be present or None.
>>> seq([('a', 1), ('b', 2)]).join([('a', 3), ('c', 4)])
[('a', (1, 3)), ('b', (2, None)]
:param other: sequence to join with
:return: left joined sequence of (K, (V, W)) pairs
"""
return self._general_join(other, "left")

def right_join(self, other):
"""
Sequence and other must be composed of (Key, Value) pairs. If self.sequence contains (K, V) pairs and
other contains (K, W) pairs, the return result is a sequence of (K, (V, W)) pairs. W values will always be
present, V values may be present or None.
>>> seq([('a', 1), ('b', 2)]).join([('a', 3), ('c', 4)])
[('a', (1, 3)), ('b', (2, None)]
:param other: sequence to join with
:return: right joined sequence of (K, (V, W)) pairs
"""
return self._general_join(other, "right")

def outer_join(self, other):
"""
Sequence and other must be composed of (Key, Value) pairs. If self.sequence contains (K, V) pairs and
other contains (K, W) pairs, the return result is a sequence of (K, (V, W)) pairs. One of V or W will always
be not None, but the other may be None
>>> seq([('a', 1), ('b', 2)]).outer_join([('a', 3), ('c', 4)], "outer")
[('a', (1, 3)), ('b', (2, None)), ('c', (None, 4))]
:param other: sequence to join with
:return: outer joined sequence of (K, (V, W)) pairs
"""
return self._general_join(other, "outer")

def partition(self, f):
"""
Partition the sequence based on satisfying the predicate f.
Expand Down
40 changes: 40 additions & 0 deletions test/test_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,13 @@ def test_drop(self):
self.assertEqual(result, expect)
self.assertTrue(result)

def test_drop_right(self):
s = seq([1, 2, 3, 4])
expect = [1, 2]
result = s.drop_right(2)
self.assertType(result)
self.assertEqual(result, expect)

def test_drop_while(self):
l = [1, 2, 3, 4, 5, 6, 7, 8]
f = lambda x: x < 4
Expand Down Expand Up @@ -332,6 +339,39 @@ def test_join(self):
self.assertType(result)
self.assertSequenceEqual(dict(result), dict(e))

def test_left_join(self):
left = [('a', 1), ('b', 2)]
right = [('a', 2), ('c', 3)]
result = seq(left).left_join(right)
expect = [('a', (1, 2)), ('b', (2, None))]
self.assertType(result)
self.assertEqual(dict(result), dict(expect))
result = seq(left).left_join(seq(right))
self.assertType(result)
self.assertEqual(dict(result), dict(expect))

def test_right_join(self):
left = [('a', 1), ('b', 2)]
right = [('a', 2), ('c', 3)]
result = seq(left).right_join(right)
expect = [('a', (1, 2)), ('c', (None, 3))]
self.assertType(result)
self.assertEqual(dict(result), dict(expect))
result = seq(left).right_join(seq(right))
self.assertType(result)
self.assertEqual(dict(result), dict(expect))

def test_outer_join(self):
left = [('a', 1), ('b', 2)]
right = [('a', 2), ('c', 3)]
result = seq(left).outer_join(right)
expect = [('a', (1, 2)), ('b', (2, None)), ('c', (None, 3))]
self.assertType(result)
self.assertEqual(dict(result), dict(expect))
result = seq(left).outer_join(seq(right))
self.assertType(result)
self.assertEqual(dict(result), dict(expect))

def test_max(self):
l = [1, 2, 3]
self.assertEqual(3, seq(l).max())
Expand Down

0 comments on commit 22367ff

Please sign in to comment.