Skip to content

Commit

Permalink
Added product, product_with and zip_with
Browse files Browse the repository at this point in the history
  • Loading branch information
WitoldFracek committed Dec 14, 2024
1 parent 7ce2796 commit 06bcef2
Show file tree
Hide file tree
Showing 2 changed files with 227 additions and 0 deletions.
76 changes: 76 additions & 0 deletions src/qwlist/eager.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

T = TypeVar('T')
K = TypeVar('K')
R = TypeVar('R')
SupportsLessThan = TypeVar("SupportsLessThan")
SupportsAdd = TypeVar("SupportsAdd")
SupportsEq = TypeVar("SupportsEq")
Expand Down Expand Up @@ -693,3 +694,78 @@ def flat_fold(self, combination: Callable[[K, T], Iterable[K]], init: K) -> "Eag
for elem in self:
acc = acc.flatmap(lambda x, e=elem: combination(x, e))
return acc

def product(self, other: Iterable[K]) -> "EagerQList[Tuple[T, K]]":
"""
Computes the Cartesian product of `self` and `other`.
Args:
other (Iterable[K]): iterable to make the cartesian product with.
Returns:
A new EagerQList of pairs from Cartesian product.
"""
def inner():
for t in self:
for k in other:
yield t, k
return EagerQList(inner())

def product_with(self, other: Iterable[K], operation: Callable[[T, K], R]) -> "EagerQList[R]":
"""
Applies a given operation to every pair of elements from the Cartesian product
of `self` and `other`, returning a new Lazy iterable of the results.
This method "lifts" the provided `operation` from working on individual elements
to working on pairs of elements produced from the Cartesian product. It is equivalent
to calling `self.product(other).map(lambda pair: operation(*pair))`.
Args:
other (Iterable[T]): The iterable to combine with `self` in a Cartesian product.
operation (Callable[[T, K], R]): `function: (T, K) -> R` that takes a pair of elements,
one from `self` and one from `other`, and returns a result of type `R`.
Returns:
A new EagerQList containing the results of applying `operation`
to each pair in the Cartesian product.
Example:
>>> list1 = EagerQList([1, 2])
>>> list2 = EagerQList(['a', 'b'])
>>> result = list1.product_with(list2, lambda x, y: f"{x}{y}")
>>> list(result)
['1a', '1b', '2a', '2b']
"""
def inner():
for t in self:
for k in other:
yield operation(t, k)
return EagerQList(inner())

def zip_with(self, other: Iterable[K], operation: Callable[[T, K], R]) -> "EagerQList[R]":
"""
Applies a given `operation` to pairs of elements from `self` and `other`, created by zipping them together.
This method "lifts" the provided `operation` from working on individual elements
to working on pairs of elements formed by zipping the two iterables. It is equivalent
to calling `self.zip(other).map(lambda pair: operation(*pair))`.
Args:
other (Iterable[K]): The iterable to zip with `self`.
operation (Callable[[T, K], R]): `function: (T, K) -> R` that takes a pair of elements,
one from `self` and one from `other`, and returns a result of type `R`.
Returns:
Lazy[R]: A new EagerQList containing the results of applying `operation`
to each pair in the zipped iterables.
Example:
>>> qlist1 = QList([1, 2, 3])
>>> qlist2 = QList(['a', 'b'])
>>> result = qlist1.zip_with(qlist2, lambda x, y: f"{x}{y}")
>>> list(result)
['1a', '2b']
"""
def inner():
for t, k in self.zip(other):
yield operation(t, k)
return EagerQList(inner())
151 changes: 151 additions & 0 deletions src/qwlist/qwlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

T = TypeVar('T')
K = TypeVar('K')
R = TypeVar('R')
SupportsLessThan = TypeVar("SupportsLessThan")
SupportsAdd = TypeVar("SupportsAdd")
SupportsEq = TypeVar("SupportsEq")
Expand Down Expand Up @@ -803,6 +804,81 @@ def flat_fold(self, combination: Callable[[K, T], Iterable[K]], init: K) -> "Laz
acc = acc.flatmap(lambda x, e=elem: combination(x, e))
return acc

def product(self, other: Iterable[K]) -> "Lazy[Tuple[T, K]]":
"""
Computes the Cartesian product of `self` and `other`.
Args:
other (Iterable[K]): iterable to make the cartesian product with.
Returns:
A new Lazy of pairs from Cartesian product.
"""
def inner():
for t in self:
for k in other:
yield t, k
return Lazy(inner())

def product_with(self, other: Iterable[K], operation: Callable[[T, K], R]) -> "Lazy[R]":
"""
Applies a given operation to every pair of elements from the Cartesian product
of `self` and `other`, returning a new Lazy iterable of the results.
This method "lifts" the provided `operation` from working on individual elements
to working on pairs of elements produced from the Cartesian product. It is equivalent
to calling `self.product(other).map(lambda pair: operation(*pair))`.
Args:
other (Iterable[T]): The iterable to combine with `self` in a Cartesian product.
operation (Callable[[T, K], R]): `function: (T, K) -> R` that takes a pair of elements,
one from `self` and one from `other`, and returns a result of type `R`.
Returns:
A new Lazy containing the results of applying `operation`
to each pair in the Cartesian product.
Example:
>>> lazy1 = Lazy([1, 2])
>>> lazy2 = Lazy(['a', 'b'])
>>> result = lazy1.product_with(lazy2, lambda x, y: f"{x}{y}")
>>> list(result)
['1a', '1b', '2a', '2b']
"""
def inner():
for t in self:
for k in other:
yield operation(t, k)
return Lazy(inner())

def zip_with(self, other: Iterable[K], operation: Callable[[T, K], R]) -> "Lazy[R]":
"""
Applies a given `operation` to pairs of elements from `self` and `other`, created by zipping them together.
This method "lifts" the provided `operation` from working on individual elements
to working on pairs of elements formed by zipping the two iterables. It is equivalent
to calling `self.zip(other).map(lambda pair: operation(*pair))`.
Args:
other (Iterable[K]): The iterable to zip with `self`.
operation (Callable[[T, K], R]): `function: (T, K) -> R` that takes a pair of elements,
one from `self` and one from `other`, and returns a result of type `R`.
Returns:
Lazy[R]: A new Lazy containing the results of applying `operation`
to each pair in the zipped iterables.
Example:
>>> lazy1 = Lazy([1, 2, 3])
>>> lazy2 = Lazy(['a', 'b'])
>>> result = lazy1.zip_with(lazy2, lambda x, y: f"{x}{y}")
>>> list(result)
['1a', '2b']
"""
def inner():
for t, k in self.zip(other):
yield operation(t, k)
return Lazy(inner())

# ---------------------------------------------- QList ----------------------------------------------

class QList(list):
Expand Down Expand Up @@ -1582,6 +1658,81 @@ def flat_fold(self, combination: Callable[[K, T], Iterable[K]], init: K) -> Lazy
acc = acc.flatmap(lambda x, e=elem: combination(x, e))
return acc

def product(self, other: Iterable[K]) -> Lazy[Tuple[T, K]]:
"""
Computes the Cartesian product of `self` and `other`.
Args:
other (Iterable[K]): iterable to make the cartesian product with.
Returns:
A new Lazy of pairs from Cartesian product.
"""
def inner():
for t in self:
for k in other:
yield t, k
return Lazy(inner())

def product_with(self, other: Iterable[K], operation: Callable[[T, K], R]) -> Lazy[R]:
"""
Applies a given operation to every pair of elements from the Cartesian product
of `self` and `other`, returning a new Lazy iterable of the results.
This method "lifts" the provided `operation` from working on individual elements
to working on pairs of elements produced from the Cartesian product. It is equivalent
to calling `self.product(other).map(lambda pair: operation(*pair))`.
Args:
other (Iterable[T]): The iterable to combine with `self` in a Cartesian product.
operation (Callable[[T, K], R]): `function: (T, K) -> R` that takes a pair of elements,
one from `self` and one from `other`, and returns a result of type `R`.
Returns:
A new Lazy containing the results of applying `operation`
to each pair in the Cartesian product.
Example:
>>> qlist1 = QList([1, 2])
>>> qlist2 = QList(['a', 'b'])
>>> result = qlist1.product_with(qlist2, lambda x, y: f"{x}{y}")
>>> list(result)
['1a', '1b', '2a', '2b']
"""
def inner():
for t in self:
for k in other:
yield operation(t, k)
return Lazy(inner())

def zip_with(self, other: Iterable[K], operation: Callable[[T, K], R]) -> Lazy[R]:
"""
Applies a given `operation` to pairs of elements from `self` and `other`, created by zipping them together.
This method "lifts" the provided `operation` from working on individual elements
to working on pairs of elements formed by zipping the two iterables. It is equivalent
to calling `self.zip(other).map(lambda pair: operation(*pair))`.
Args:
other (Iterable[K]): The iterable to zip with `self`.
operation (Callable[[T, K], R]): `function: (T, K) -> R` that takes a pair of elements,
one from `self` and one from `other`, and returns a result of type `R`.
Returns:
Lazy[R]: A new Lazy containing the results of applying `operation`
to each pair in the zipped iterables.
Example:
>>> qlist1 = QList([1, 2, 3])
>>> qlist2 = QList(['a', 'b'])
>>> result = qlist1.zip_with(qlist2, lambda x, y: f"{x}{y}")
>>> list(result)
['1a', '2b']
"""
def inner():
for t, k in self.zip(other):
yield operation(t, k)
return Lazy(inner())


if __name__ == '__main__':
def naturals(start):
Expand Down

0 comments on commit 06bcef2

Please sign in to comment.